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