1781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckipackage signtool; 2781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 3781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.io.*; 4781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.util.Properties; 5781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.util.ArrayList; 6781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 7781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.internet.*; 8781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.MessagingException; 9781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.Session; 10781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.activation.MailcapCommandMap; 11781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.activation.CommandMap; 12781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 13781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.PrivateKey; 14781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.Security; 15781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.KeyFactory; 16781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.KeyStore; 17781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.NoSuchAlgorithmException; 18781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.spec.PKCS8EncodedKeySpec; 19781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.spec.InvalidKeySpecException; 20781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.X509Certificate; 21781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateFactory; 22781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.Certificate; 23781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateException; 24781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateEncodingException; 25781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 26781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.jce.provider.BouncyCastleProvider; 27781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; 28781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; 29781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.ContentSigner; 30781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; 31781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSProcessableByteArray; 32781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedGenerator; 33781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedDataGenerator; 34781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedGenerator; 35781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSProcessable; 36781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedData; 37781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSTypedData; 38781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cert.jcajce.JcaCertStore; 39781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.util.Store; 40781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.ASN1InputStream; 41781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.DEROutputStream; 42781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.ASN1Object; 43781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 44781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 45781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckipublic class SignImg { 46781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 47781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki /* It reads private key in pkcs#8 formate 48781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki * Conversion: 49781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8 50781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki */ 51781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException { 52781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(path); 53781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileInputStream fis = new FileInputStream(file); 54781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki byte[] data = new byte[(int)file.length()]; 55781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.read(data); 56781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.close(); 57781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 58781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data); 59781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki KeyFactory kf = KeyFactory.getInstance("RSA"); 60781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki PrivateKey privateKey = kf.generatePrivate(kspec); 61781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 62781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return privateKey; 63781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 64781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 65781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException { 66781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki MimeBodyPart body = new MimeBodyPart(); 67781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 68781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(path); 69781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileInputStream fis = new FileInputStream(file); 70781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki byte[] data = new byte[(int)file.length()]; 71781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.read(data); 72781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.close(); 73781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 74781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki body.setContent(data, "application/octet-stream"); 75781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 76781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return body; 77781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 78781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 79781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException { 80781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(path); 81781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileInputStream fis = new FileInputStream(file); 82781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki byte[] data = new byte[(int)file.length()]; 83781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.read(data); 84781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki fis.close(); 85781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CMSProcessableByteArray cms = new CMSProcessableByteArray(data); 86781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 87781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return cms; 88781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 89781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 90781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException { 91781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(path); 92781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileInputStream is = new FileInputStream(file); 93781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 94781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CertificateFactory cf = CertificateFactory.getInstance("X.509"); 95781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki Certificate cert = cf.generateCertificate(is); 96781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki is.close(); 97781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 98781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return (X509Certificate) cert; 99781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 100781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 101781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException { 102781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(path); 103781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileOutputStream os = new FileOutputStream(file); 104781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 105781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki content.writeTo(os); 106781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 107781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki os.close(); 108781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 109781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 110781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException { 111781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(); 112781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki certList.add(certificate); 113781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return new JcaCertStore(certList); 114781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 115781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 116781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki public static void setDefaultMailcap() 117781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki { 118781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki MailcapCommandMap _mailcap = 119781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki (MailcapCommandMap)CommandMap.getDefaultCommandMap(); 120781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 121781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature"); 122781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime"); 123781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature"); 124781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime"); 125781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed"); 126781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 127781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CommandMap.setDefaultCommandMap(_mailcap); 128781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 129781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 130781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki public static void main(String[] args) { 131781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki try { 132781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki if (args.length < 4) { 133781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Usage: signimg data private_key certificate output"); 134781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki return; 135781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 136781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Signing the image"); 137781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki setDefaultMailcap(); 138781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 139781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki Security.addProvider(new BouncyCastleProvider()); 140781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 141781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki PrivateKey key = getPrivateKey(args[1]); 142781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("File read sucessfully"); 143781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 144781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); 145781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 146781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CMSTypedData body = getCMSContent(args[0]); 147781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Content read sucessfully"); 148781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 149781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki X509Certificate cert = (X509Certificate) readCert(args[2]); 150781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Certificate read sucessfully"); 151781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 152781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key); 153781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 154781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki Store certs = certToStore(cert); 155781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 156781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki generator.addCertificates(certs); 157781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki generator.addSignerInfoGenerator( 158781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki new JcaSignerInfoGeneratorBuilder( 159781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) 160781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki .build(sha256Signer, cert)); 161781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 162781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki CMSSignedData signed = generator.generate(body, true); 163781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Signed"); 164781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 165781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki Properties props = System.getProperties(); 166781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki Session session = Session.getDefaultInstance(props, null); 167781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 168781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki File file = new File(args[3]); 169781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki FileOutputStream os = new FileOutputStream(file); 170781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 171781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded()); 172781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki ByteArrayOutputStream out = new ByteArrayOutputStream(); 173781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki DEROutputStream dOut = new DEROutputStream(os); 174781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded())); 175781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki 176781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 177781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki catch (Exception ex) { 178781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki System.out.println("Exception during programm execution: " + ex.getMessage()); 179781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 180781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki } 181781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki} 182