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/DemoUtil.java 29    12.02.25 17:58 Dbratko $
029// $Revision: 29 $
030//
031
032package demo;
033
034import java.io.IOException;
035import java.security.AlgorithmParameters;
036import java.security.InvalidAlgorithmParameterException;
037import java.security.MessageDigest;
038import java.security.NoSuchAlgorithmException;
039import java.security.Provider;
040import java.security.Security;
041import java.security.spec.InvalidParameterSpecException;
042import java.util.Random;
043
044import iaik.asn1.ObjectID;
045import iaik.asn1.structures.AlgorithmID;
046import iaik.cms.SecurityProvider;
047import iaik.pkcs.pkcs1.MGF1ParameterSpec;
048import iaik.pkcs.pkcs1.MaskGenerationAlgorithm;
049import iaik.pkcs.pkcs1.RSAPssParameterSpec;
050import iaik.security.provider.IAIK;
051import iaik.security.random.MetaSeedGenerator;
052import iaik.security.random.SecRandom;
053import iaik.security.random.SeedGenerator;
054
055/**
056 * Some basic utility methods used by the demos.
057 */
058public class DemoUtil {
059  
060  /** Debug flag for all demos */
061  public final static boolean DEMO_DEBUG = true;
062  
063  /**
064   * Base OID for IAIK-CMS demos.
065   */
066  public final static ObjectID IAIK_JAVA_SECURITY_DEMO_CMS_OID = new ObjectID("1.3.6.1.4.1.2706.2.2.4", "IAIK JavaSecurity CMS Demo");
067  
068  /**
069   * Greeting message.
070   */
071  final static String[] GREETING = {
072    "*                                                                            *",
073    "*         Welcome to the IAIK-CMS/SMIMEv4 Demo Programs                      *",
074    "*                                                                            *",
075    "* These simple programs show how to use the IAIK-CMS library. Please         *", 
076    "* see  the  documentation and  the source code  for more information.        *",
077    "*                                                                            *",
078    "*                                                                            *",
079    "* NOTE that most of the demos require certificates to work, they are         *", 
080    "* taken from a keystore file (cms.keystore) located  in your current         *",
081    "* working directory. If yet not exist, the keystore can be generated         *",
082    "* by calling demo.keystore.SetupCMSKeyStore.                                 *",
083    "*                                                                            *",
084    "",
085  };
086
087  
088  /**
089   * Whether to {@link demo.keystore.SetupCMSKeyStore create} a new demo keystore automatically
090   * if it is not present or to explicitly ask if to create it.
091   */
092  public static boolean CREATE_DEMO_KEYSTORE_AUTOMATICAllY = false;
093  /**
094   * Initialization done?
095   */
096  static boolean initialized_ = false;
097  
098  /**
099   * Version number of the IAIK-JCE crypto provider.
100   */
101  static double iaikProviderVersion_ = -1;
102  
103  /**
104   * Empty constructor.
105   */
106  DemoUtil() {
107    // empty
108  }
109  
110  /** Perform a some initial setup to allow the demos to work */
111  public synchronized static void initDemos() {
112    initDemos(true);
113  }
114  
115  /**
116   *  Perform a some initial setup to allow the demos to work
117   *  
118   *  @param quickStart whether to init the random generator with a
119   *                    (not strong) seed for quick start (ONLY FOR 
120   *                    DEMO PURPOSES; NOT FOR PRODUCTION ENVIRONMENT!)
121   */
122  public synchronized static void initDemos(boolean quickStart) {
123    
124    if( initialized_ ) {
125      return;
126    }
127    initialized_ = true;
128    for( int i=0; i<GREETING.length; i++ ) {
129      System.out.println(GREETING[i]);
130    }
131    initRandom(quickStart);
132    addIaikProvider();
133  }
134  
135
136  /**
137   * Adds the IAIK JCE as a first security provider. 
138   */
139  public static void addIaikProvider() {
140    IAIK.addAsProvider();
141    Provider iaikProv = Security.getProvider("IAIK");
142    iaikProviderVersion_ = iaikProv.getVersion();
143  }
144  
145  /**
146   * Gets the version number of the IAIK-JCE provider used for this demos.
147   *
148   * @return the version number of the IAIK JCA/JCE provider
149   */
150  public static double getIaikProviderVersion() {
151    if (iaikProviderVersion_ == -1) {
152      addIaikProvider();   
153    }    
154    return iaikProviderVersion_; 
155  }  
156  
157  /**
158   * Adds the cryptography provider with the given name.
159   *
160   * Note that it may <em>not</em> be enough to just add it as a provider;
161   * see the {@link iaik.cms.SecurityProvider SecurityProvider} class for more information.
162   *
163   * @param name the name of the provider to be added
164   */
165  public static void addProvider(String name) {
166    try {
167      Class clazz = Class.forName(name);
168      Provider provider = (Provider)clazz.newInstance();
169      Security.addProvider(provider);
170    } catch (ClassNotFoundException ex) {
171      System.out.println("Provider IAIK not found. Add iaik_jce.jar or iaik_jce_full.jar to your classpath.");
172      System.out.println("If you are going to use a different provider please take a look at Readme.html!");
173      System.exit(0);
174    } catch (Exception ex) {
175      System.out.println("Error adding provider:");
176      ex.printStackTrace(System.err);
177      System.exit(0);
178    }
179  }
180  
181  /**
182   * Setup the random number generator for a quick start.
183   * THIS IS NOT SECURE AND SHOULD BE USED FOR DEMO PURPOSES ONLY.
184   * ANY CRYPTOGRAPHIC KEY DERIVED IN THIS WAY IS WEAK AND NO STRONGER THAN 20 BIT!!!
185   */
186  public static void initRandom() {
187    System.out.println("Quick-starting random number generator (not for use in production systems!)...");
188    Random random = new Random();
189    byte[] seed = new byte[20];
190    random.nextBytes(seed);
191    MetaSeedGenerator.setSeed(seed);
192    SeedGenerator.setDefault(MetaSeedGenerator.class);
193  }
194  
195  /**
196   * Setup the random number generator for a quick start.
197   * THIS IS NOT SECURE AND SHOULD BE USED FOR DEMO PURPOSES ONLY.
198   * ANY CRYPTOGRAPHIC KEY DERIVED IN THIS WAY IS WEAK AND NO STRONGER THAN 20 BIT!!!
199   * 
200   * @param quick whether to init the random generator with a (not strong) seed 
201   *                for quick start (only for demonstration purposes)
202   */
203  public static void initRandom(boolean quick) {
204    if (quick) {
205      System.out.println("Quick-starting random number generator (not for use in production systems!)...");
206      Random random = new Random();
207      byte[] seed = new byte[20];
208      random.nextBytes(seed);
209      MetaSeedGenerator.setSeed(seed);
210      SeedGenerator.setDefault(MetaSeedGenerator.class);
211    } else {
212      // create a new Thread which initializes the Secure Random Number generator
213      (new Thread() {
214        public void run() {
215          setPriority(Thread.MIN_PRIORITY);
216          SecRandom.getDefault().nextInt();
217        }
218      }).start();
219    }
220  }
221  
222  /**
223   * Creates a RSA-PSS AlgorithmID with the supplied parameters (hash algorithm id,
224   * mask generation function, salt length).
225   *
226   * @param hashID the hash algorithm to be used
227   * @param mgfID the mask generation function to be used
228   * @param saltLength the salt length to be used
229   *
230   * @return the RSA-PSS algorithm id with the given parameters 
231   *
232   * @throws InvalidAlgorithmParameterException if the parameters cannot be created/set
233   * @throws NoSuchAlgorithmException if there is no AlgorithmParameters implementation
234   *                                     for RSA-PSS
235   */
236  public static AlgorithmID createPssAlgorithmID(AlgorithmID hashID, AlgorithmID mgfID, int saltLength)
237    throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
238        
239    SecurityProvider provider = SecurityProvider.getSecurityProvider();
240    AlgorithmID rsaPssID = (AlgorithmID)AlgorithmID.rsassaPss.clone();
241    mgfID.setParameter(hashID.toASN1Object());
242    // create a RSAPssParameterSpec
243    RSAPssParameterSpec pssParamSpec = new RSAPssParameterSpec(hashID, mgfID, saltLength);
244    // optionally set hash and mgf engines
245    MessageDigest hashEngine = provider.getMessageDigest(hashID);
246    pssParamSpec.setHashEngine(hashEngine);
247    MaskGenerationAlgorithm mgfEngine = provider.getMaskGenerationAlgorithm(mgfID);
248    MGF1ParameterSpec mgf1Spec = new MGF1ParameterSpec(hashID);
249    mgf1Spec.setHashEngine(hashEngine);
250    mgfEngine.setParameters(mgf1Spec);
251    pssParamSpec.setMGFEngine(mgfEngine);
252  
253    AlgorithmParameters pssParams = null;
254    try {
255      pssParams = provider.getAlgorithmParameters(SecurityProvider.IMPLEMENTATION_NAME_RSA_PSS);
256      pssParams.init(pssParamSpec);
257  
258  
259    } catch (InvalidParameterSpecException ex) {
260      throw new InvalidAlgorithmParameterException("Cannot init PSS params: " + ex.getMessage());  
261    }    
262   
263    rsaPssID.setAlgorithmParameters(pssParams);
264    return rsaPssID;
265  }  
266  
267  
268  /**
269   * Wait for the user to press the return key on System.in.
270   */
271  public static void waitKey() {
272    try {
273      System.out.println("Hit the <RETURN> key.");
274      do {
275        System.in.read();
276      } while( System.in.available() > 0 );
277    } catch( IOException e ) {
278      // ignore
279    }
280  }
281  
282}