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/cms/pkcs11/IaikPkcs11SecurityProvider.java 11    12.02.25 17:58 Dbratko $
059    //
060    
061    package demo.cms.pkcs11;
062    
063    import java.security.InvalidAlgorithmParameterException;
064    import java.security.InvalidKeyException;
065    import java.security.Key;
066    import java.security.NoSuchAlgorithmException;
067    import java.security.NoSuchProviderException;
068    import java.security.PrivateKey;
069    import java.security.PublicKey;
070    import java.security.SecureRandom;
071    import java.security.Signature;
072    import java.security.SignatureException;
073    import java.security.spec.AlgorithmParameterSpec;
074    
075    import javax.crypto.BadPaddingException;
076    import javax.crypto.Cipher;
077    import javax.crypto.IllegalBlockSizeException;
078    import javax.crypto.NoSuchPaddingException;
079    import javax.crypto.SecretKey;
080    
081    import iaik.asn1.structures.AlgorithmID;
082    import iaik.cms.CMSAlgorithmID;
083    import iaik.cms.DigestInfo;
084    import iaik.cms.IaikProvider;
085    import iaik.pkcs.pkcs1.RSAPssParameterSpec;
086    import iaik.pkcs.pkcs11.Mechanism;
087    import iaik.pkcs.pkcs11.parameters.RSAPkcsParameters;
088    import iaik.pkcs.pkcs11.parameters.RSAPkcsPssParameters;
089    import iaik.pkcs.pkcs11.provider.IAIKPkcs11;
090    import iaik.pkcs.pkcs11.provider.keys.IAIKPKCS11Key;
091    import iaik.pkcs.pkcs11.provider.keys.IAIKPKCS11PrivateKey;
092    import iaik.pkcs.pkcs11.provider.signatures.PKCS11SignatureParameterSpec;
093    import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
094    
095    
096    
097    /**
098     * This class implements a <code>SecurityProvider</code> for the IAIK-CMS
099     * toolkit. This <code>SecurityProvider</code> can handle
100     * <code>IAIKPKCS11Key</code> objects and is thus suitable for use with the
101     * PKCS#11 provider. The demos in this package use this class to get the
102     * IAIK-CMS library to use a PKCS#11 module instead of pure software crypto.
103     * <p>
104     * To install this security provider call:
105     * <pre>
106     * IAIKPkcs11 iaikPkcs11Provider = ...;
107     * IaikPkcs11SecurityProvider pkcs11CmsSecurityProvider = new IaikPkcs11SecurityProvider(iaikPkcs11Provider);
108     * SecurityProvider.setSecurityProvider(pkcs11CmsSecurityProvider);
109     * </pre>
110     */
111    public class IaikPkcs11SecurityProvider extends IaikProvider {
112    
113      /**
114       * Switch on/off debug output.
115       */
116      private final static boolean DEBUG = true;
117    
118      /**
119       * The name of the security provider.
120       */
121      private final static String PROVIDER_NAME = "IAIK PKCS#11 Security Provider";
122    
123      /**
124       * Reference to the installed PKCS#11 provider instance.
125       */
126      protected IAIKPkcs11 iaikPkcs11Provider_;
127    
128      /**
129       * The given PKCS#11 provider instance must already be installed in the JCA 
130       * framework.
131       * 
132       * @param iaikPkcs11Provider The PKCS#11 provider instance to use in this CMS
133       *                           security provider. 
134       */
135      public IaikPkcs11SecurityProvider(IAIKPkcs11 iaikPkcs11Provider) {
136        super();
137        // providerName_ = PROVIDER_NAME;
138        iaikPkcs11Provider_ = iaikPkcs11Provider;
139      }
140    
141      /**
142       * Calculates the signature value for a CMS SignerInfo over the given digest
143       * value with the given algorithm using the supplied private key.
144       * <p>
145       * Each {@link iaik.cms.SignerInfo SignerInfo} included in a CMS SignedData
146       * object may calculate the signature value differently depending on the
147       * presence of signed attributes:
148       * <p>
149       * <ul>
150       * <li>If signed attributes are present the signature is calculated over
151       *     the DER encoding of the signed attributes.
152       * <li>If signed attributes are NOT present, the signature is calculated
153       *     over the content data itsself.
154       * </ul>
155       * This method is called by class {@link iaik.cms.SignerInfo SignerInfo} for
156       * calculating the signature when no signed attributes are present. Since
157       * the data to be signed may be of arbitrary size this method expects the
158       * already hashed data to only calculate the signature value on it (for
159       * instance, by doing the digest encrypting when using RSA for signing).
160       * <p>
161       * For that reason, when writing your own SecurityProvider and overriding
162       * this method, you will need some kind of <i>RAW</i> signature (respectively
163       * digest encryption) mechanism only expecting the already hashed data (e.g.
164       * a "RawDSA" signature engine when using DSA repectively a Cipher engine
165       * when using RSA).
166       * <p>
167       * If you want to override this method for use with smartcards, please be sure
168       * that your smartcard is able to do the signature (respectively digest
169       * encryption) operation only. However, if your smartcard requires to supply
170       * the whole data for doing the hash calcualtion itself, you may ensure that
171       * your {@link iaik.cms.SignerInfo SignerInfo} contains signed attributes
172       * and override method {@link #calculateSignatureFromSignedAttributes
173       * calculateSignatureFromSignedAttributes} for calculating the signature over
174       * the DER encoding of the signed attributes (thereby doing the hash
175       * computation, too).
176       *
177       * @param signatureAlgorithm signatureAlgorithm the signature algorithm to be
178       *        used, e.g. rsaEncryption, DSA
179       * @param digestAlgorithm the digest algorithm used for hash computation (e.g.
180       *        SHA-1 or MD5); may be necessary for some signature schemes (e.g.
181       *        to be included as a DigestInfo in a PKCS#1 RSA signature)
182       * @param privateKey the private key of the signer (i.e. the one supplied when
183       *        creating a {@link iaik.cms.SignerInfo SignerInfo} object; may be
184       *        some kind of "dummy" key when used for smartcards
185       * @param digest the digest value over which the signature shall be calculated
186       *
187       * @return the signature value calculated from the given digest value
188       *
189       * @throws NoSuchAlgorithmException if any of the required algorithms is not supported
190       * @throws InvalidKeyException if the key is not valid
191       * @throws SignatureException if signature verification fails because of some crypto related error
192       */
193      public byte[] calculateSignatureFromHash(AlgorithmID signatureAlgorithm,
194        AlgorithmID digestAlgorithm, PrivateKey privateKey, byte[] digest)
195          throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
196      {
197        byte[] signatureValue;
198    
199        // we handle PKCS#11 keys in a special way, but we forward other keys to the default implementation
200        if (privateKey instanceof IAIKPKCS11PrivateKey) {
201          IAIKPkcs11 iaikPkcs11KeyProvider = ((IAIKPKCS11PrivateKey) privateKey).getTokenManager().getProvider();
202    
203          String algorithmName = privateKey.getAlgorithm();
204    
205          Signature signatureEngine;
206          byte[] dataToBeSigned = digest;
207          try {
208            if (algorithmName.equals("RSA")) {
209              if (signatureAlgorithm.equals(CMSAlgorithmID.rsassaPss)) {   
210                signatureEngine = Signature.getInstance("RawRSA/PSS", iaikPkcs11KeyProvider.getName());
211                PKCS11SignatureParameterSpec params = generateRSAPssParameters(digestAlgorithm, signatureAlgorithm);
212                try {
213                  signatureEngine.setParameter(params);
214                } catch (InvalidAlgorithmParameterException e) {
215                  throw new SignatureException("Error setting RSA-PSS algorithm parameters: " + e.toString());
216                }
217              } else {
218                DigestInfo digestInfo = new DigestInfo(digestAlgorithm, digest);
219                dataToBeSigned = digestInfo.toByteArray();
220                signatureEngine = Signature.getInstance("RawRSA/PKCS1", iaikPkcs11KeyProvider.getName());
221              }  
222            } else if (algorithmName.equals("DSA")) {
223              signatureEngine = Signature.getInstance("RawDSA", iaikPkcs11KeyProvider.getName());
224            } else if ((algorithmName.equals("EC")) || (algorithmName.equals("ECDSA"))) {
225              signatureEngine = Signature.getInstance("RawECDSA", iaikPkcs11KeyProvider.getName());
226            } else {
227              throw new NoSuchAlgorithmException(
228                "Unable to calculate signature with signature algorithm: " + signatureAlgorithm);
229            }
230            
231          } catch (NoSuchProviderException ex) {
232            throw new NoSuchAlgorithmException("The PKCS#11 provider has not been installed corerctly: " + ex);
233          }
234          signatureEngine.initSign(privateKey);
235          signatureEngine.update(dataToBeSigned);
236          signatureValue = signatureEngine.sign();
237        } else {
238          signatureValue = super.calculateSignatureFromHash(signatureAlgorithm, digestAlgorithm, privateKey, digest);
239        }
240    
241        return signatureValue ;
242      }
243      
244      /**
245       * Calculates the signature value for a CMS SignerInfo over the given signed 
246       * attributes with the given algorithm using the supplied private key.
247       * <p>
248       * Each {@link iaik.cms.SignerInfo SignerInfo} included in a CMS SignedData
249       * object may calculate the signature value differently depending on the
250       * presence of signed attributes:
251       * <p>
252       * <ul>
253       * <li>If signed attributes are present the signature is calculated over
254       *     the DER encoding of the signed attributes. 
255       * <li>If signed attributes are NOT present, the signature is calculated
256       *     over the content data itsself.
257       * </ul>
258       * This method is called by class {@link iaik.cms.SignerInfo SignerInfo} for
259       * calculating the signature when signed attributes are present. 
260       * <p>
261       * When writing your own SecurityProvider and overriding
262       * this method, be aware that only the -- yet NOT hashed -- DER encoding of
263       * the signed attributes is supplied to this method. For that reason this
264       * method can be overriden for use with smartcards requiring to do the 
265       * digest calculation theirselves: ensure that your {@link iaik.cms.SignerInfo
266       * SignerInfo} contains signed attributes and override this method in a way
267       * to pass the given DER encoding of the signed attributes to your smartcard
268       * for doing the signature (and digest) calculation.
269       * <p>
270       * Since this method requires to calculate the digest value over the DER encoded
271       * signed attributes as part of the signature calculation, it uses a 
272       * ordinary JCA Signature engine.
273       *
274       * @param signatureAlgorithm signatureAlgorithm the signature algorithm to be
275       *        used, e.g. rsaEncryption, DSA
276       * @param digestAlgorithm the digest algorithm to be used for hash computation (e.g.
277       *        SHA-1,..., SHA-512); may be necessary for some signature schemes (e.g.
278       *        to be included as a DigestInfo in a PKCS#1 RSA signature)
279       * @param privateKey the private key of the signer (i.e. the one supplied when
280       *        creating a {@link iaik.cms.SignerInfo SignerInfo} object; may be
281       *        some kind of "dummy" key when used for smartcards
282       * @param signedAttributes the DER encoding of the signed attributes over which 
283       *        the signature shall be calculated
284       *
285       * @return the signature value calculated from the given DER encoded signed
286       *         attributes
287       *
288       * @throws NoSuchAlgorithmException if no Signature engine is available for the requested algorithm
289       * @throws InvalidKeyException if the key is not valid
290       * @throws SignatureException if signature calculation fails
291       */
292      public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, 
293        AlgorithmID digestAlgorithm, PrivateKey privateKey, byte[] signedAttributes) 
294        throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
295          
296        byte[] digest = getHash(digestAlgorithm, signedAttributes);
297        return calculateSignatureFromHash(signatureAlgorithm, digestAlgorithm, privateKey, digest);
298    
299      }  
300    
301      /**
302       * This method returns the desired Signature object which uses the PKCS#11
303       * provider if the key is a PKCS#11 key.
304       *
305       * If the mode parameter is <CODE>SIGNATURE_SIGN</CODE> or 
306       * <CODE>SIGNATURE_VERIFY</CODE> the signature object has to be
307       * initialized with the provided key in the respective mode.
308       *
309       * @param algorithm the name of the Signature algorithm
310       * @param mode the mode indicating if the engine has to be initialized
311       * @param key the key for initializing the Signature engine
312       *
313       * @return the (if requested initialized) Signature engine
314       *
315       * @throws InvalidKeyException if the key is not valid 
316       * @throws NoSuchAlgorithmException if no Signature engine is
317       *            available for the requested algorithm
318       */
319      public Signature getSignature(String algorithm, int mode, Key key) 
320        throws InvalidKeyException, NoSuchAlgorithmException {
321            
322        Signature signature;
323        
324        // for PKCS#11 keys we use the PKCS#11 provider, for other keys we use the default implementation
325        if (key instanceof IAIKPKCS11Key) {
326          try {
327            signature = Signature.getInstance(algorithm, iaikPkcs11Provider_.getName());
328          } catch (NoSuchProviderException e) {
329            throw new NoSuchAlgorithmException("PKCS#11 Provider has not been installed correctly " + e.toString());
330          }  
331          if (mode == SIGNATURE_SIGN) {
332            signature.initSign((PrivateKey)key);
333          } else if (mode == SIGNATURE_VERIFY) {
334            signature.initVerify((PublicKey)key);
335          } // do nothing for SIGNATURE_NONE
336        } else {
337          signature = super.getSignature(algorithm, mode, key);  
338        }
339        
340        return signature ;
341      }
342      
343      /**
344       * This method returns the desired Signature object.
345       *
346       * If the mode parameter is <CODE>SIGNATURE_SIGN</CODE> or 
347       * <CODE>SIGNATURE_VERIFY</CODE> the signature object is to be
348       * initialized with the provided key in the respective mode.
349       * If algorithm parameters are specified they are set for the
350       * Signature engine.
351       *
352       * @param algorithm the AlgorithmID of the Signature algorithm
353       * @param mode the mode indicating if the engine has to be initialized
354       * @param key the key for initializing the Signature engine
355       * @param paramSpec any parameters to be set for the Signature engine, if not <code>null</code>
356       *
357       * @return the (if requested initialized) Signature engine
358       *
359       * @throws InvalidKeyException if the key is not valid 
360       * @throws NoSuchAlgorithmException if no Signature engine is
361       *            available for the requested algorithm
362       */
363      public Signature getSignature(AlgorithmID algorithm, 
364                                    int mode, 
365                                    Key key,
366                                    AlgorithmParameterSpec paramSpec) 
367       throws InvalidKeyException, NoSuchAlgorithmException {
368        
369        Signature signature;
370        
371        // for PKCS#11 keys we use the PKCS#11 provider, for other keys we use the default implementation
372        if (key instanceof IAIKPKCS11Key) {
373         
374          signature = algorithm.getSignatureInstance(iaikPkcs11Provider_.getName());
375            
376          if (mode == SIGNATURE_SIGN) {
377            signature.initSign((PrivateKey)key);
378          } else if (mode == SIGNATURE_VERIFY) {
379            signature.initVerify((PublicKey)key);
380          } // do nothing for SIGNATURE_NONE
381        } else {
382          signature = super.getSignature(algorithm, mode, key, paramSpec);  
383        }
384        if (paramSpec != null) {
385          setSignatureParameters(signature, paramSpec);
386        }
387        return signature ;
388        
389      }
390      
391      /**
392       * Calculates RSA-PSS parameters for the given digest algorithm
393       * 
394       * @param digestAlgorithm the digest algorithm
395       * @param signatureAlgorithm the signature algorithm
396       * 
397       * @return the generated parameters
398       * 
399       * @throws NoSuchAlgorithmException if no parameters for the given digest algorithms are available
400       */
401       private static PKCS11SignatureParameterSpec generateRSAPssParameters(
402           AlgorithmID digestAlgorithm, AlgorithmID signatureAlgorithm) 
403         throws NoSuchAlgorithmException {
404         
405         
406         Mechanism hashAlgorithm;
407         long messageGenerationFunctionType;
408         int saltLength;
409         if (digestAlgorithm.equals(AlgorithmID.sha1)) {
410           hashAlgorithm = Mechanism.get(PKCS11Constants.CKM_SHA_1);
411           messageGenerationFunctionType = RSAPkcsParameters.MessageGenerationFunctionType.SHA1;
412           saltLength = 20;
413         } else if (digestAlgorithm.equals(AlgorithmID.sha256)) {
414           hashAlgorithm = Mechanism.get(PKCS11Constants.CKM_SHA256);
415           messageGenerationFunctionType = RSAPkcsParameters.MessageGenerationFunctionType.SHA256;
416           saltLength = 32;
417         } else if (digestAlgorithm.equals(AlgorithmID.sha384)) {
418           hashAlgorithm = Mechanism.get(PKCS11Constants.CKM_SHA384);
419           messageGenerationFunctionType = RSAPkcsParameters.MessageGenerationFunctionType.SHA384;
420           saltLength = 48;
421         } else if (digestAlgorithm.equals(AlgorithmID.sha512)) {
422           hashAlgorithm = Mechanism.get(PKCS11Constants.CKM_SHA512);
423           messageGenerationFunctionType = RSAPkcsParameters.MessageGenerationFunctionType.SHA512;
424           saltLength = 64;
425         } else {
426           throw new NoSuchAlgorithmException(
427               "Cannot create RSA-PSS parameters for " + digestAlgorithm.getName()
428                   + " digest algorithm!");
429         }
430         RSAPkcsPssParameters parameters = new RSAPkcsPssParameters(
431             hashAlgorithm, messageGenerationFunctionType, saltLength);
432         PKCS11SignatureParameterSpec params = new PKCS11SignatureParameterSpec(
433             parameters);
434         
435         // set signature algorithm parameters
436         AlgorithmID mgf1 = (AlgorithmID)AlgorithmID.mgf1.clone(); 
437         mgf1.setParameter(digestAlgorithm.toASN1Object());
438         RSAPssParameterSpec pssParamSpec = new RSAPssParameterSpec(digestAlgorithm, 
439             mgf1, saltLength);
440         try {
441           signatureAlgorithm.setAlgorithmParameterSpec(pssParamSpec);
442         } catch (InvalidAlgorithmParameterException e) {
443           throw new NoSuchAlgorithmException(e.toString());
444         }
445         return params;
446       }
447     
448      /**
449       * Decrypts the given encrypted content encryption key for a {@link 
450       * iaik.cms.KeyTransRecipientInfo KeyTransRecipientInfo}.
451       * <p>
452       * CMS <code>EnvelopedData</code> uses the {@link 
453       * iaik.cms.KeyTransRecipientInfo KeyTransRecipientInfo} type for
454       * encrypting the secret content encryption key with the public key of
455       * the recipient. Currently in general RSA PKCS#1v1.5 is used for key
456       * transport. If rsaEncryption is requested as key encryption algorithm
457       * this method uses a RSA Cipher ("RSA/ECB/PKCS1Padding/Encrypt") for
458       * decrypting the encrypted content encryption key with the supplied 
459       * private key of the recipient. If another algorithm than RSA is requested,
460       * this method throws a NoSuchAlgorithmException. An application wishing to
461       * support another algorithm may override this method.
462       *
463       * @param encryptedKey the encrypted content encryption key to be decrypted
464       * @param kea the key encryption alglorithm to be used, e.g. rsaEncryption
465       * @param recipientKey the private key of the recipient to be used for decrypting
466       *                     the encrypted content encryption key
467       * @param cekAlgorithmName the name of the content encryption key (e.g. "DES") to be set for the
468       *                         SecretKey object created by this method
469       *
470       * @return the decrypted content encryption key
471       *
472       * @throws NoSuchAlgorithmException if the requested algorithm is not available
473       * @throws InvalidKeyException if the decryption key is not valid
474       * @throws NoSuchPaddingException if the required padding scheme is not supported
475       * @throws BadPaddingException if an padding error occurs
476       */
477      public SecretKey decryptKey(byte[] encryptedKey, AlgorithmID kea, PrivateKey recipientKey, String cekAlgorithmName) 
478        throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, BadPaddingException 
479      {
480        SecretKey decryptedSymmetricKey;
481    
482        // we handle PKCS#11 keys in a special way, but we forward other keys to the default implementation
483        if (recipientKey instanceof IAIKPKCS11PrivateKey) {
484          IAIKPkcs11 iaikPkcs11KeyProvider = ((IAIKPKCS11PrivateKey) recipientKey).getTokenManager().getProvider();
485          String algorithmImplementationName = kea.getImplementationName();
486    
487          try {
488            Cipher cipher = Cipher.getInstance(algorithmImplementationName, iaikPkcs11KeyProvider.getName());
489            cipher.init(Cipher.DECRYPT_MODE, recipientKey, (AlgorithmParameterSpec) null, (SecureRandom) null);
490            byte[] cek = cipher.doFinal(encryptedKey);
491            decryptedSymmetricKey = new iaik.security.cipher.SecretKey(cek, cekAlgorithmName);
492            
493          } catch (NoSuchProviderException ex) {
494            throw new NoSuchAlgorithmException("The PKCS#11 provider has not been installed corerctly: " + ex);
495          } catch (InvalidAlgorithmParameterException ex) {
496            throw new NoSuchAlgorithmException("Error initializing the cipher: " + ex);
497          } catch (IllegalBlockSizeException ex) {
498            throw new NoSuchAlgorithmException("Error during cipher operation: " + ex);
499          }
500        } else {
501          decryptedSymmetricKey = super.decryptKey(encryptedKey, kea, recipientKey, cekAlgorithmName);
502        }
503    
504        return decryptedSymmetricKey ;
505      }
506    
507      /**
508       * Decrypts the given encrypted content encryption key for a {@link 
509       * iaik.cms.KeyTransRecipientInfo KeyTransRecipientInfo}.
510       * <p>
511       * CMS <code>EnvelopedData</code> uses the {@link 
512       * iaik.cms.KeyTransRecipientInfo KeyTransRecipientInfo} type for
513       * encrypting the secret content encryption key with the public key of
514       * the recipient. Currently in general RSA PKCS#1v1.5 is used for key
515       * transport. If rsaEncryption is requested as key encryption algorithm
516       * this method uses a RSA Cipher ("RSA/ECB/PKCS1Padding/Encrypt") for
517       * decrypting the encrypted content encryption key with the supplied 
518       * private key of the recipient. If another algorithm than RSA is requested,
519       * this method throws a NoSuchAlgorithmException. An application wishing to
520       * support another algorithm may override this method.
521       *
522       * @param encryptedKey the encrypted content encryption key to be decrypted
523       * @param kea the key encryption alglorithm to be used, e.g. rsaEncryption
524       * @param recipientKey the private key of the recipient to be used for decrypting
525       *                     the encrypted content encryption key
526       *
527       * @return the decrypted content encryption key, the algorithm name will be set to "RAW"
528       *
529       * @throws NoSuchAlgorithmException if the requested algorithm is not available
530       * @throws InvalidKeyException if the decryption key is not valid
531       * @throws NoSuchPaddingException if the required padding scheme is not supported
532       * @throws BadPaddingException if an padding error occurs
533       */
534    // only needed for old CMS versions
535    //  public SecretKey decryptKey(byte[] encryptedKey, AlgorithmID kea, PrivateKey recipientKey) 
536    //    throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, BadPaddingException 
537    //  {
538    //    return decryptKey(encryptedKey, kea, recipientKey, "RAW"); 
539    //  }
540        
541    }