001// Copyright (C) 2002 IAIK
002// https://sic.tech/
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// This source is provided for inspection purposes and recompilation only,
011// unless specified differently in a contract with IAIK. This source has to
012// be kept in strict confidence and must not be disclosed to any third party
013// under any circumstances. Redistribution in source and binary forms, with
014// or without modification, are <not> permitted in any case!
015//
016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
026// SUCH DAMAGE.
027//
028// $Header: /IAIK-CMS/current/src/demo/smime/ecc/SMimeV4BrainpoolDemo.java 3     12.02.25 17:59 Dbratko $
029// $Revision: 3 $
030//
031
032package demo.smime.ecc;
033
034import java.security.PrivateKey;
035
036import jakarta.activation.DataHandler;
037import jakarta.mail.Session;
038
039import demo.DemoSMimeUtil;
040import demo.DemoUtil;
041import demo.cms.ecc.ECCDemoUtil;
042import demo.cms.ecc.keystore.CMSEccKeyStore;
043import iaik.asn1.structures.AlgorithmID;
044import iaik.cms.CMSAlgorithmID;
045import iaik.utils.KeyAndCertificate;
046import iaik.x509.X509Certificate;
047
048/**
049 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
050 * signed and/or (authenticated) encrypted S/MIMEv4 messages using ECC keys with Berainpool curves
051 * and how to parse them and verify the signatures and decrypt the content, respectively.
052 * <p>
053 * Although Brainpool curves may not be widely used with S/MIME applications they are, e.g., recommended 
054 * by the German Federal Office for Information Security (BSI) for their Technical Guideline BSI TR-03116
055 * defining cryptographic requirements for projects of the Federal Government.
056 * Note that whereas S/MIME in general uses AEAD cipher modes like GCM with the <code>AuthEnvelopedData</code>
057 * content type, BSI TR-03116 specifies GCM for use with the <code>EnvelopedData</code> type. For that 
058 * reason GCM is used with <code>EnvelopedData</code> in this demo (in difference to the parent 
059 * {@link SMimeV4EccDemo SMimeV4EccDemo} which uses GCM with the <code>AuthEnvelopedData</code> type.
060 *   
061 * <p>
062 * Additionally to <code>iaik_cms.jar</code> you also must have 
063 * <code>iaik_jce_(full).jar</code> (IAIK-JCE, <a href =
064 * "https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">
065 * https://sic.tech/products/core-crypto-toolkits/jca-jce/</a>),
066 * and <code>iaik_eccelarate.jar</code> (IAIK-ECCelerate<sup><small>TM</small></sup>, <a href =
067 * "https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">
068 * https://sic.tech/products/core-crypto-toolkits/eccelerate/</a>)
069 * in your classpath.
070 * <p>
071 * To run this demo the following packages are required:
072 * <ul>
073 *    <li>
074 *       <code>iaik_cms.jar</code>
075 *    </li>
076 *    <li>
077 *       <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>).
078 *    </li>
079 *    <li>
080 *       <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>).
081 *    </li>   
082 *    <li>
083 *       <a href="https://jakarta.ee/specifications/mail/" target="_blank">Jakarta</a>/<a href="https://eclipse-ee4j.github.io/angus-mail/" target="_blank">Angus</a> Mail
084 *    </li>   
085 *    <li>
086 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
087 *    </li> 
088 * </ul>
089 * 
090 * This demo requires Java 7 or later.
091 */
092public class SMimeV4BrainpoolDemo extends SMimeV4EccDemo {
093    
094 
095  /**
096   * Default constructor.
097   */
098  public SMimeV4BrainpoolDemo() {
099    
100    System.out.println();
101    System.out.println("********************************************************************************************");
102    System.out.println("*                                SMimeV4EccDemo demo                                       *");
103    System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIMEv4 messages) *");
104    System.out.println("********************************************************************************************");
105    System.out.println();
106
107  }
108  
109   
110  /**
111   * Starts the demo.
112   *
113   * @throws Exception if an error occurs
114   */
115  public void start() throws Exception {
116    
117    // get the default Session
118    Session session = DemoSMimeUtil.getSession();
119
120    // Create a demo Multipart
121    DataHandler multipart = createMultipart();
122    
123    // get signer key and certs
124    KeyAndCertificate[] signerKeyAndCerts = {
125        // Brainpool P-224
126        new KeyAndCertificate(
127            CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA,
128                CMSEccKeyStore.SZ_224_BRAINPOOL_SIGN),
129            CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA,
130                CMSEccKeyStore.SZ_224_BRAINPOOL_SIGN)),
131
132        // Brainpool P-256
133        new KeyAndCertificate(
134            CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA,
135                CMSEccKeyStore.SZ_256_BRAINPOOL_SIGN),
136            CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA,
137                CMSEccKeyStore.SZ_256_BRAINPOOL_SIGN)),
138        // Brainpool P-384
139        new KeyAndCertificate(
140            CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA,
141                CMSEccKeyStore.SZ_384_BRAINPOOL_SIGN),
142            CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA,
143                CMSEccKeyStore.SZ_384_BRAINPOOL_SIGN)),
144        // Brainpool P-512
145        new KeyAndCertificate(
146            CMSEccKeyStore.getPrivateKey(CMSEccKeyStore.ECDSA,
147                CMSEccKeyStore.SZ_512_BRAINPOOL_SIGN),
148            CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDSA,
149                CMSEccKeyStore.SZ_512_BRAINPOOL_SIGN)),
150
151     };
152     
153     // the digest and signature algorithms to be used
154     AlgorithmID[][] digestAndSignatureAlgorithms = new AlgorithmID[][] {
155       { CMSAlgorithmID.sha224, CMSAlgorithmID.ecdsa_With_SHA224 },
156       { CMSAlgorithmID.sha256, CMSAlgorithmID.ecdsa_With_SHA256 },
157       { CMSAlgorithmID.sha384, CMSAlgorithmID.ecdsa_With_SHA384 },
158       { CMSAlgorithmID.sha512, CMSAlgorithmID.ecdsa_With_SHA512 },
159     };
160
161    
162     /**************************************************************************/
163     /*                                                                        */
164     /*                               Signing Demo                             */
165     /*                                                                        */
166     /**************************************************************************/
167     
168     final int DIGEST_ALG = 0;
169     final int SIGNATURE_ALG = 1;
170     for (int i = 0; i < digestAndSignatureAlgorithms.length; i++) {
171       AlgorithmID digestAlg = digestAndSignatureAlgorithms[i][DIGEST_ALG];
172       AlgorithmID signatureAlg = digestAndSignatureAlgorithms[i][SIGNATURE_ALG];
173       PrivateKey signerKey = signerKeyAndCerts[i].getPrivateKey();
174       X509Certificate[] signerCerts = signerKeyAndCerts[i].getCertificateChain();
175       System.out.println("Running signing demo for " + signatureAlg.getName());
176       startSigningDemo(session, 
177                        multipart, 
178                        digestAlg, 
179                        signatureAlg, 
180                        signerKey,
181                        signerCerts);
182    }
183     
184    // (authenticated) encryption demos
185     
186    // get recipient certs
187    X509Certificate[] recipientCerts = {
188        // Brainpool P-224
189        CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
190                CMSEccKeyStore.SZ_224_BRAINPOOL_CRYPT_1)[0],
191        CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
192            CMSEccKeyStore.SZ_224_BRAINPOOL_CRYPT_2)[0],
193       // Brainpool P-256
194       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
195               CMSEccKeyStore.SZ_256_BRAINPOOL_CRYPT_1)[0],
196       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
197               CMSEccKeyStore.SZ_256_BRAINPOOL_CRYPT_2)[0],
198       // Brainpool P-384
199       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
200               CMSEccKeyStore.SZ_384_BRAINPOOL_CRYPT_1)[0],
201       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
202               CMSEccKeyStore.SZ_384_BRAINPOOL_CRYPT_2)[0],
203       //Brainpool P-512
204       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
205               CMSEccKeyStore.SZ_512_BRAINPOOL_CRYPT_1)[0],
206       CMSEccKeyStore.getCertificateChain(CMSEccKeyStore.ECDH,
207               CMSEccKeyStore.SZ_512_BRAINPOOL_CRYPT_2)[0],
208       
209    };
210     
211    //  the key encryption algorithms to be used
212    AlgorithmID[] keyEAs = {
213        AlgorithmID.dhSinglePass_stdDH_sha224kdf_scheme, 
214        AlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme, 
215        AlgorithmID.dhSinglePass_stdDH_sha384kdf_scheme, 
216        AlgorithmID.dhSinglePass_stdDH_hkdf_sha256_scheme, 
217        AlgorithmID.dhSinglePass_stdDH_hkdf_sha384_scheme,
218        AlgorithmID.dhSinglePass_stdDH_hkdf_sha512_scheme, 
219    };
220    // key wrap algorithms
221    AlgorithmID[] keyWrapAlgs = {
222        CMSAlgorithmID.cms_aes128_wrap, 
223        CMSAlgorithmID.cms_aes192_wrap, 
224        CMSAlgorithmID.cms_aes256_wrap, 
225    };
226    // whether to encrypt or authenticated encrypt
227    boolean[] doAuthEncrypt = { false, true };
228    for (int i = 0; i < keyEAs.length; i++) {
229      AlgorithmID[] contentEAs;
230      AlgorithmID keyEA = keyEAs[i];
231      for (int j = 0; j < keyWrapAlgs.length; j++) {
232        AlgorithmID keyWrapAlg = keyWrapAlgs[j];
233        int kekLength;
234        int keyLength;
235        if (keyWrapAlg.equals(CMSAlgorithmID.cms_aes192_wrap)) {
236          kekLength = 192;
237          keyLength = 192;
238          contentEAs = new AlgorithmID[]  { AlgorithmID.aes192_GCM, AlgorithmID.aes192_CCM };
239        } else if (keyWrapAlg.equals(CMSAlgorithmID.cms_aes128_wrap)) {
240          kekLength = 128;
241          keyLength = 128;
242          contentEAs = new AlgorithmID[]  { AlgorithmID.aes128_GCM, AlgorithmID.aes128_CCM  };
243        } else {
244          kekLength = 256;
245          keyLength = 256;
246          contentEAs = new AlgorithmID[]  { AlgorithmID.aes256_GCM, AlgorithmID.aes256_CCM, AlgorithmID.chacha20Poly1305 };
247        }
248        
249        for (int k = 0; k < contentEAs.length; k++) {
250          
251          /**************************************************************************/
252          /*                                                                        */
253          /*                  (Authenticated) Encryption Demo                       */
254          /*                                                                        */
255          /**************************************************************************/
256          
257          AlgorithmID contentEA = contentEAs[k];
258          // in practice we may not create one message for recipients with different strength;
259          // however, for simplicity we use all recipients here
260          System.out.println("Running encryption demo for " + 
261                              keyEA.getName() + " with " + keyWrapAlg.getName() +" and " + contentEA.getName());
262          startEncryptionDemo(session,
263                              contentEA, 
264                              keyLength, 
265                              keyEA,
266                              keyWrapAlg,
267                              kekLength,
268                              false, 
269                              recipientCerts);
270          
271          
272          /**************************************************************************/
273          /*                                                                        */
274          /*             Signing and (Authenticated) Encryption Demo                */
275          /*                                                                        */
276          /**************************************************************************/
277          
278          for (int l = 0; l < digestAndSignatureAlgorithms.length; l++) {
279            AlgorithmID digestAlg = digestAndSignatureAlgorithms[l][DIGEST_ALG];
280            AlgorithmID signatureAlg = digestAndSignatureAlgorithms[l][SIGNATURE_ALG];
281            PrivateKey signerKey = signerKeyAndCerts[l].getPrivateKey();
282            X509Certificate[] signerCerts = signerKeyAndCerts[l].getCertificateChain();
283            System.out.println("Running signing and encryption and demo for " + signatureAlg.getName());
284            startSigningAndEncryptionDemo(session,
285                multipart,
286                digestAlg,
287                signatureAlg,
288                contentEA, 
289                keyLength, 
290                keyEA,
291                keyWrapAlg,
292                kekLength,
293                false,  
294                signerKey, 
295                signerCerts,
296                recipientCerts);
297          }
298        }
299      }
300    }
301     
302  } 
303 
304  /**
305   * The main method.
306   */
307  public static void main(String[] argv) throws Exception {
308    
309    String jdkVersion = (String) System.getProperty("java.version");
310    if (jdkVersion.compareTo("1.7") >= 0) {
311      DemoSMimeUtil.initDemos();
312      //  add ECC provider    
313      ECCDemoUtil.installIaikEccProvider();
314      
315        (new SMimeV4BrainpoolDemo()).start();
316      System.out.println("\nReady!");
317    } else {
318      System.err.println("This demo requires Java 7 or later!");
319    }
320    DemoUtil.waitKey();
321  }
322}