001 // Copyright (C) 2002 IAIK 002 // https://jce.iaik.tugraz.at 003 // 004 // Copyright (C) 2003 - 2025 Stiftung Secure Information and 005 // Communication Technologies SIC 006 // https://sic.tech 007 // 008 // All rights reserved. 009 // 010 // Redistribution and use in source and binary forms, with or without 011 // modification, are permitted provided that the following conditions 012 // are met: 013 // 1. Redistributions of source code must retain the above copyright 014 // notice, this list of conditions and the following disclaimer. 015 // 2. Redistributions in binary form must reproduce the above copyright 016 // notice, this list of conditions and the following disclaimer in the 017 // documentation and/or other materials provided with the distribution. 018 // 019 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 020 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 023 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 024 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 025 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 026 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 027 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 028 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 029 // SUCH DAMAGE. 030 031 // Copyright (C) 2002 IAIK 032 // https://sic.tech/ 033 // 034 // Copyright (C) 2003 - 2025 Stiftung Secure Information and 035 // Communication Technologies SIC 036 // https://sic.tech/ 037 // 038 // All rights reserved. 039 // 040 // This source is provided for inspection purposes and recompilation only, 041 // unless specified differently in a contract with IAIK. This source has to 042 // be kept in strict confidence and must not be disclosed to any third party 043 // under any circumstances. Redistribution in source and binary forms, with 044 // or without modification, are <not> permitted in any case! 045 // 046 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 047 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 048 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 049 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 050 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 051 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 052 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 053 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 054 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 055 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 056 // SUCH DAMAGE. 057 // 058 // $Header: /IAIK-CMS/current/src/demo/smime/pkcs11/EncryptedMailDemo.java 19 12.02.25 17:59 Dbratko $ 059 // $Revision: 19 $ 060 // 061 062 package demo.smime.pkcs11; 063 064 // class and interface imports 065 import iaik.asn1.structures.AlgorithmID; 066 import iaik.cms.CMSException; 067 import iaik.smime.EncryptedContent; 068 import iaik.smime.SMimeBodyPart; 069 import iaik.smime.SMimeMultipart; 070 import iaik.smime.SMimeUtil; 071 import iaik.utils.Util; 072 import iaik.x509.X509Certificate; 073 074 import java.io.ByteArrayInputStream; 075 import java.io.ByteArrayOutputStream; 076 import java.io.IOException; 077 import java.security.GeneralSecurityException; 078 import java.security.Key; 079 import java.security.NoSuchAlgorithmException; 080 import java.security.PrivateKey; 081 import java.security.cert.Certificate; 082 import java.security.interfaces.RSAPrivateKey; 083 import java.util.Date; 084 import java.util.Enumeration; 085 086 import javax.activation.DataHandler; 087 import javax.activation.FileDataSource; 088 import javax.mail.Message; 089 import javax.mail.MessagingException; 090 import javax.mail.Multipart; 091 import javax.mail.Session; 092 import javax.mail.internet.InternetAddress; 093 import javax.mail.internet.MimeBodyPart; 094 import javax.mail.internet.MimeMessage; 095 096 import demo.DemoSMimeUtil; 097 import demo.DemoUtil; 098 import demo.cms.pkcs11.PKCS11Demo; 099 import demo.smime.DumpMessage; 100 101 102 103 /** 104 * This class shows how to en- and decrypt an S/MIME message 105 * using the PKCS#11 provider for accessing the private key 106 * on a smart card. This implementation uses the <code>SecurityProvider</code> 107 * feature of the CMS implementation of the IAIK-CMS toolkit. 108 * <p> 109 * To run this demo the following packages are required: 110 * <ul> 111 * <li> 112 * <code>iaik_cms.jar</code> 113 * </li> 114 * <li> 115 * <code>iaik_jce(_full).jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">IAIK-JCE Core Crypto Library</a>). 116 * </li> 117 * <li> 118 * <code>iaikPkcs11Provider.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/pkcs11-provider/" target="_blank">IAIK PKCS#11 Provider</a>). 119 * </li> 120 * <li> 121 * <code>iaikPkcs11Wrapper.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/pkcs11-wrapper/" target="_blank">IAIK PKCS#11 Wrapper</a>). 122 * </li> 123 * <li> 124 * The shared PKCS#11 library (<code>pkcs11wrapper.dll</code> for Windows, <code>libpkcs11wrapper.so</code> for Unix); contained in the IAIK PKCS#11 Wrapper library. 125 * </li> 126 * <li> 127 * <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>, if you want to use Elliptic Curve Cryptography). 128 * </li> 129 * <li> 130 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>). 131 * </li> 132 * <li> 133 * <code>activation.jar</code> (<a href="http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html" target="_blank">Java Activation Framework</a>; required for JDK versions < 1.6). 134 * </li> 135 * </ul> 136 * <code>iaik_cms.jar</code>, <code>iaik_cms_demo.jar</code>, <code>iaik_jce(full).jar</code>, 137 * <code>iaikPkcs11Wrapper.jar</code> and <code>iaikPkcs11Provider.jar</code> (and 138 * <code>iaik_eccelerate.jar</code>, <code>mail.jar</code>, <code>activation.jar</code>) have to be put 139 * into the classpath, the shared library (<code>pkcs11wrapper.dll</code> or <code>libpkcs11wrapper.so</code>) 140 * has to be in your system library search path or in your VM library path, e.g. (on Windows, 141 * assuming that all jar files are located in a lib sub-directory and the dll is in a lib/win64 142 * sub-directory): 143 * <pre> 144 * java -Djava.library.path=lib/win64 145 * -cp lib/iaik_jce.jar;lib/iaikPkcs11Wrapper.jar;lib/iaikPkcs11Provider.jar;lib/iaik_cms.jar;lib/iaik_cms_demo.jar;lib/mail.jar;lib/activation.jar 146 * demo.pkcs11.EncryptedMailDemo <pkcs11Module>.dll 147 * </pre> 148 */ 149 public class EncryptedMailDemo extends PKCS11Demo { 150 151 //whether to print dump all generates test messages to System.out 152 final static boolean PRINT_MESSAGES = true; 153 154 /** 155 * Default email address. Used in this demo if the recipient certificate 156 * does not contain an email address. 157 */ 158 private final static String DEFAULT_EMAIL = "smimetest@iaik.tugraz.at"; 159 160 161 /** 162 * The private key of the recipient. In this case only a proxy object, but the 163 * application cannot see this. Used for decryption. 164 */ 165 protected PrivateKey privateKey_; 166 167 /** 168 * The certificate of the recipient. In contrast to the private key, the 169 * certificate holds holds the actual (public) keying material. 170 * Used for encryption. 171 */ 172 protected X509Certificate certificate_; 173 174 /** 175 * The email address of the sender. 176 */ 177 protected String sender_; 178 179 /** 180 * The email address of the recipient. 181 */ 182 protected String recipient_; 183 184 /** 185 * Creates a EncryptedMailDemo object for the given module name. 186 * 187 * @param moduleName the name of the module 188 * @param userPin the user-pin (password) for the TokenKeyStore 189 * (may be <code>null</code> to pou-up a dialog asking for the pin) 190 */ 191 public EncryptedMailDemo(String moduleName, char[] userPin) { 192 // install provider in super class 193 super(moduleName, userPin); 194 System.out.println(); 195 System.out.println("************************************************************************************************************"); 196 System.out.println("* PKCS#11 EncryptedMailDemo *"); 197 System.out.println("* (shows how to en/decrypt S/MIME messages using the IAIK-PKCS11 provider for accessing the key on a card) *"); 198 System.out.println("************************************************************************************************************"); 199 System.out.println(); 200 } 201 202 203 /** 204 * This method gets the key store of the PKCS#11 provider and searches for a 205 * certificate and corresponding private key entry that can en/decrypt the data. 206 * Key and cert are stored in the <code>privateKey_</code> and <code>certificate_</code> 207 * member variables. Usually you only will have the smartcard on the decryption 208 * side (i.e. the sender will get the certificate by other means to use it 209 * for encrypting the message), however, for simplicity (and since we do not know 210 * which certificate/card you are actually will use for running the demo) we 211 * get both, key and certificate from the card. 212 * 213 * @throws GeneralSecurityException If anything with the provider fails. 214 * @throws IOException If loading the key store fails. 215 */ 216 public void getKeyAndCertificate() 217 throws GeneralSecurityException, IOException, CMSException 218 { 219 220 // we simply take the first keystore, if there are serveral 221 Enumeration aliases = tokenKeyStore_.aliases(); 222 223 PrivateKey privateKey = null; 224 X509Certificate certificate = null; 225 // and we take the first private key for simplicity 226 while (aliases.hasMoreElements()) { 227 String keyAlias = aliases.nextElement().toString(); 228 Key key = null; 229 try { 230 key = tokenKeyStore_.getKey(keyAlias, null); 231 } catch (NoSuchAlgorithmException ex) { 232 throw new GeneralSecurityException(ex.toString()); 233 } 234 if (key instanceof RSAPrivateKey) { 235 Certificate[] certificateChain = tokenKeyStore_.getCertificateChain(keyAlias); 236 if ((certificateChain != null) && (certificateChain.length > 0)) { 237 X509Certificate[] certificates = Util.convertCertificateChain(certificateChain); 238 X509Certificate userCertificate = certificates[0]; 239 boolean[] keyUsage = userCertificate.getKeyUsage(); 240 if ((keyUsage == null) || keyUsage[2] || keyUsage[3]) { // check for encryption, but also accept if none set 241 // check if there is a receipient info for this certificate 242 certificate = userCertificate; 243 privateKey = (PrivateKey)key; 244 // email address included in recipient certificate? 245 String[] emailAddresses = SMimeUtil.getEmailAddresses(certificates[0]); 246 if (emailAddresses.length > 0) { 247 // in this demo we use same email for sender and recipient 248 sender_ = emailAddresses[0]; 249 recipient_ = emailAddresses[0]; 250 privateKey_ = privateKey; 251 certificate_ = certificate; 252 break; 253 } 254 255 } 256 } 257 } 258 } 259 260 if (privateKey_ == null) { 261 if (privateKey == null) { 262 System.out.println("Found no decryption key. Ensure that the correct card is inserted and contains a key that is suitable for decryption."); 263 System.exit(0); 264 } 265 // we did not find a certificate containing an email address 266 privateKey_ = privateKey; 267 certificate_ = certificate; 268 // use default address 269 sender_ = DEFAULT_EMAIL; 270 recipient_ = DEFAULT_EMAIL; 271 } 272 System.out.println("##########"); 273 System.out.println("The decrpytion key is: " + privateKey_); 274 System.out.println("##########"); 275 System.out.println("##########"); 276 System.out.println("The encryption certificate is:"); 277 System.out.println(certificate_.toString()); 278 System.out.println("##########"); 279 } 280 281 282 /** 283 * Creates an encrypted message. 284 * 285 * @param session the mail session 286 * @param dataHandler the content of the message to be encrypted 287 * 288 * @return the encrypted message 289 * 290 * @throws MessagingException if an error occurs when creating the message 291 */ 292 protected MimeMessage createEncryptedMessage(Session session, DataHandler dataHandler) 293 throws MessagingException { 294 295 String subject = "IAIK-S/MIME PKCS11 Demo: Encrypted Mail"; 296 String text = "This message is encrypted with AES!\n"; 297 298 299 // create EncryptedContent object 300 EncryptedContent ec = new EncryptedContent(); 301 302 if (dataHandler != null) { 303 ec.setDataHandler(dataHandler); 304 } else { 305 ec.setText(text); 306 } 307 308 ec.addRecipient(certificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone()); 309 try { 310 ec.setEncryptionAlgorithm((AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256); 311 } catch (NoSuchAlgorithmException ex) { 312 throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage()); 313 } 314 315 316 // create MimeMessage 317 MimeMessage msg = new MimeMessage(session); 318 msg.setFrom(new InternetAddress(sender_)); 319 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient_, false)); 320 msg.setSentDate(new Date()); 321 msg.setSubject(subject); 322 // set encrypted content 323 msg.setContent(ec, ec.getContentType()); 324 // let the EncryptedContent update some message headers 325 ec.setHeaders(msg); 326 return msg; 327 } 328 329 330 /** 331 * Starts the demo. 332 */ 333 public void start() { 334 try { 335 Session session = DemoSMimeUtil.getSession(); 336 getKeyStore(); 337 getKeyAndCertificate(); 338 // Create a demo contentMultipart 339 MimeBodyPart mbp1 = new SMimeBodyPart(); 340 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 341 // attachment 342 MimeBodyPart attachment = new SMimeBodyPart(); 343 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 344 attachment.setFileName("test.html"); 345 346 Multipart mp = new SMimeMultipart(); 347 mp.addBodyPart(mbp1); 348 mp.addBodyPart(attachment); 349 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 350 351 // create signed message 352 MimeMessage msg = createEncryptedMessage(DemoSMimeUtil.getSession(), multipart); 353 354 // we write to a stream 355 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 356 msg.saveChanges(); 357 msg.writeTo(baos); // here you could call Transport.send if you want to send the message 358 359 // we read from a stream 360 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 361 // parse message 362 msg = new MimeMessage(session, bais); 363 if (PRINT_MESSAGES) { 364 printMessage(msg); 365 } 366 DumpMessage dumpMsg = new DumpMessage(); 367 dumpMsg.setRecipientKey(privateKey_); 368 dumpMsg.dump(msg); 369 System.out.println("##########"); 370 } catch (Throwable ex) { 371 ex.printStackTrace(); 372 throw new RuntimeException(ex.toString()); 373 } 374 } 375 376 /** 377 * This is the main method that is called by the JVM during startup. 378 * 379 * @param args These are the command line arguments. 380 */ 381 public static void main(String[] args) { 382 383 if (args.length == 0) { 384 System.out.println("Missing pkcs11 module name.\n"); 385 printUsage(); 386 } 387 388 String moduleName = args[0]; 389 char[] userPin = (args.length == 2) ? args[1].toCharArray() : null; 390 391 if (args.length > 2) { 392 System.out.println("Too many arguments.\n"); 393 printUsage(); 394 } 395 396 DemoSMimeUtil.initDemos(); 397 398 (new EncryptedMailDemo(moduleName, userPin)).start();; 399 System.out.println("Ready!"); 400 DemoUtil.waitKey(); 401 } 402 403 /** 404 * Prints a dump of the given message to System.out. 405 * 406 * @param msg the message to be dumped to System.out 407 */ 408 private static void printMessage(Message msg) throws IOException { 409 System.out.println("------------------------------------------------------------------"); 410 System.out.println("Message dump: \n"); 411 try { 412 msg.writeTo(System.out); 413 } catch (MessagingException ex) { 414 throw new IOException(ex.getMessage()); 415 } 416 System.out.println("\n------------------------------------------------------------------"); 417 } 418 419 /** 420 * Print usage information. 421 */ 422 private final static void printUsage() { 423 System.out.println("Usage:\n"); 424 System.out.println("java EncryptedMailDemo <pkcs11 module name> [<user-pin>]\n"); 425 System.out.println("e.g.:"); 426 System.out.println("java EncryptedMailDemo aetpkss1.dll"); 427 System.out.println("java EncryptedMailDemo aetpkss1.so"); 428 DemoUtil.waitKey(); 429 System.exit(0); 430 } 431 432 433 434 435 }