1 package org.bouncycastle.cert.crmf.jcajce; 2 3 import java.io.IOException; 4 import java.security.AlgorithmParameterGenerator; 5 import java.security.AlgorithmParameters; 6 import java.security.GeneralSecurityException; 7 import java.security.InvalidAlgorithmParameterException; 8 import java.security.InvalidKeyException; 9 import java.security.Key; 10 import java.security.KeyFactory; 11 import java.security.MessageDigest; 12 import java.security.NoSuchAlgorithmException; 13 import java.security.NoSuchProviderException; 14 import java.security.PublicKey; 15 import java.security.SecureRandom; 16 import java.security.spec.InvalidKeySpecException; 17 import java.security.spec.InvalidParameterSpecException; 18 import java.security.spec.X509EncodedKeySpec; 19 import java.util.HashMap; 20 import java.util.Map; 21 22 import javax.crypto.Cipher; 23 import javax.crypto.KeyGenerator; 24 import javax.crypto.Mac; 25 import javax.crypto.NoSuchPaddingException; 26 import javax.crypto.SecretKey; 27 import javax.crypto.spec.IvParameterSpec; 28 import javax.crypto.spec.RC2ParameterSpec; 29 30 import org.bouncycastle.asn1.ASN1Encodable; 31 import org.bouncycastle.asn1.ASN1Null; 32 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 33 import org.bouncycastle.asn1.ASN1OctetString; 34 import org.bouncycastle.asn1.ASN1Primitive; 35 import org.bouncycastle.asn1.DERBitString; 36 import org.bouncycastle.asn1.DERNull; 37 import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; 38 import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; 39 import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; 40 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 41 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 42 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 43 import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; 44 import org.bouncycastle.cert.crmf.CRMFException; 45 import org.bouncycastle.cms.CMSAlgorithm; 46 import org.bouncycastle.cms.CMSEnvelopedDataGenerator; 47 import org.bouncycastle.jcajce.util.JcaJceHelper; 48 49 class CRMFHelper 50 { 51 protected static final Map BASE_CIPHER_NAMES = new HashMap(); 52 protected static final Map CIPHER_ALG_NAMES = new HashMap(); 53 protected static final Map DIGEST_ALG_NAMES = new HashMap(); 54 protected static final Map KEY_ALG_NAMES = new HashMap(); 55 protected static final Map MAC_ALG_NAMES = new HashMap(); 56 57 static 58 { BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, R)59 BASE_CIPHER_NAMES.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE"); BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, R)60 BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, R)61 BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, R)62 BASE_CIPHER_NAMES.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); 63 CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, R)64 CIPHER_ALG_NAMES.put(CMSAlgorithm.DES_EDE3_CBC, "DESEDE/CBC/PKCS5Padding"); CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, R)65 CIPHER_ALG_NAMES.put(CMSAlgorithm.AES128_CBC, "AES/CBC/PKCS5Padding"); CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, R)66 CIPHER_ALG_NAMES.put(CMSAlgorithm.AES192_CBC, "AES/CBC/PKCS5Padding"); CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, R)67 CIPHER_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AES/CBC/PKCS5Padding"); CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), R)68 CIPHER_ALG_NAMES.put(new ASN1ObjectIdentifier(PKCSObjectIdentifiers.rsaEncryption.getId()), "RSA/ECB/PKCS1Padding"); 69 DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, R)70 DIGEST_ALG_NAMES.put(OIWObjectIdentifiers.idSHA1, "SHA1"); DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, R)71 DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha224, "SHA224"); DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, R)72 DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha256, "SHA256"); DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, R)73 DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha384, "SHA384"); DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, R)74 DIGEST_ALG_NAMES.put(NISTObjectIdentifiers.id_sha512, "SHA512"); 75 MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, R)76 MAC_ALG_NAMES.put(IANAObjectIdentifiers.hmacSHA1, "HMACSHA1"); MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, R)77 MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA1, "HMACSHA1"); MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, R)78 MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HMACSHA224"); MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, R)79 MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HMACSHA256"); MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, R)80 MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HMACSHA384"); MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, R)81 MAC_ALG_NAMES.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HMACSHA512"); 82 KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, R)83 KEY_ALG_NAMES.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, R)84 KEY_ALG_NAMES.put(X9ObjectIdentifiers.id_dsa, "DSA"); 85 } 86 87 private JcaJceHelper helper; 88 CRMFHelper(JcaJceHelper helper)89 CRMFHelper(JcaJceHelper helper) 90 { 91 this.helper = helper; 92 } 93 toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo)94 PublicKey toPublicKey(SubjectPublicKeyInfo subjectPublicKeyInfo) 95 throws CRMFException 96 { 97 98 try 99 { 100 X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPublicKeyInfo).getBytes()); 101 AlgorithmIdentifier keyAlg = subjectPublicKeyInfo.getAlgorithmId(); 102 return createKeyFactory(keyAlg.getAlgorithm()).generatePublic(xspec); 103 } 104 catch (IOException e) 105 { 106 throw new CRMFException("invalid key: " + e.getMessage(), e); 107 } 108 catch (InvalidKeySpecException e) 109 { 110 throw new CRMFException("invalid key: " + e.getMessage(), e); 111 } 112 } 113 createCipher(ASN1ObjectIdentifier algorithm)114 Cipher createCipher(ASN1ObjectIdentifier algorithm) 115 throws CRMFException 116 { 117 try 118 { 119 String cipherName = (String)CIPHER_ALG_NAMES.get(algorithm); 120 121 if (cipherName != null) 122 { 123 try 124 { 125 // this is reversed as the Sun policy files now allow unlimited strength RSA 126 return helper.createCipher(cipherName); 127 } 128 catch (NoSuchAlgorithmException e) 129 { 130 // Ignore 131 } 132 } 133 return helper.createCipher(algorithm.getId()); 134 } 135 catch (NoSuchPaddingException e) 136 { 137 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 138 } 139 catch (NoSuchAlgorithmException e) 140 { 141 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 142 } 143 catch (NoSuchProviderException e) 144 { 145 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 146 } 147 } 148 createKeyGenerator(ASN1ObjectIdentifier algorithm)149 public KeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm) 150 throws CRMFException 151 { 152 try 153 { 154 String cipherName = (String)BASE_CIPHER_NAMES.get(algorithm); 155 156 if (cipherName != null) 157 { 158 try 159 { 160 // this is reversed as the Sun policy files now allow unlimited strength RSA 161 return helper.createKeyGenerator(cipherName); 162 } 163 catch (NoSuchAlgorithmException e) 164 { 165 // Ignore 166 } 167 } 168 return helper.createKeyGenerator(algorithm.getId()); 169 } 170 catch (NoSuchAlgorithmException e) 171 { 172 throw new CRMFException("cannot create key generator: " + e.getMessage(), e); 173 } 174 catch (NoSuchProviderException e) 175 { 176 throw new CRMFException("cannot create key generator: " + e.getMessage(), e); 177 } 178 } 179 createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID)180 Cipher createContentCipher(final Key sKey, final AlgorithmIdentifier encryptionAlgID) 181 throws CRMFException 182 { 183 return (Cipher)execute(new JCECallback() 184 { 185 public Object doInJCE() 186 throws CRMFException, InvalidAlgorithmParameterException, 187 InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException, 188 NoSuchPaddingException, NoSuchProviderException 189 { 190 Cipher cipher = createCipher(encryptionAlgID.getAlgorithm()); 191 ASN1Primitive sParams = (ASN1Primitive)encryptionAlgID.getParameters(); 192 String encAlg = encryptionAlgID.getAlgorithm().getId(); 193 194 if (sParams != null && !(sParams instanceof ASN1Null)) 195 { 196 try 197 { 198 AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm()); 199 200 try 201 { 202 params.init(sParams.getEncoded(), "ASN.1"); 203 } 204 catch (IOException e) 205 { 206 throw new CRMFException("error decoding algorithm parameters.", e); 207 } 208 209 cipher.init(Cipher.DECRYPT_MODE, sKey, params); 210 } 211 catch (NoSuchAlgorithmException e) 212 { 213 if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) 214 || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) 215 || encAlg.equals(CMSEnvelopedDataGenerator.AES128_CBC) 216 || encAlg.equals(CMSEnvelopedDataGenerator.AES192_CBC) 217 || encAlg.equals(CMSEnvelopedDataGenerator.AES256_CBC)) 218 { 219 cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec( 220 ASN1OctetString.getInstance(sParams).getOctets())); 221 } 222 else 223 { 224 throw e; 225 } 226 } 227 } 228 else 229 { 230 if (encAlg.equals(CMSEnvelopedDataGenerator.DES_EDE3_CBC) 231 || encAlg.equals(CMSEnvelopedDataGenerator.IDEA_CBC) 232 || encAlg.equals(CMSEnvelopedDataGenerator.CAST5_CBC)) 233 { 234 cipher.init(Cipher.DECRYPT_MODE, sKey, new IvParameterSpec(new byte[8])); 235 } 236 else 237 { 238 cipher.init(Cipher.DECRYPT_MODE, sKey); 239 } 240 } 241 242 return cipher; 243 } 244 }); 245 } 246 247 AlgorithmParameters createAlgorithmParameters(ASN1ObjectIdentifier algorithm) 248 throws NoSuchAlgorithmException, NoSuchProviderException 249 { 250 String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); 251 252 if (algorithmName != null) 253 { 254 try 255 { 256 // this is reversed as the Sun policy files now allow unlimited strength RSA 257 return helper.createAlgorithmParameters(algorithmName); 258 } 259 catch (NoSuchAlgorithmException e) 260 { 261 // Ignore 262 } 263 } 264 return helper.createAlgorithmParameters(algorithm.getId()); 265 } 266 267 KeyFactory createKeyFactory(ASN1ObjectIdentifier algorithm) 268 throws CRMFException 269 { 270 try 271 { 272 String algName = (String)KEY_ALG_NAMES.get(algorithm); 273 274 if (algName != null) 275 { 276 try 277 { 278 // this is reversed as the Sun policy files now allow unlimited strength RSA 279 return helper.createKeyFactory(algName); 280 } 281 catch (NoSuchAlgorithmException e) 282 { 283 // Ignore 284 } 285 } 286 return helper.createKeyFactory(algorithm.getId()); 287 } 288 catch (NoSuchProviderException e) 289 { 290 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 291 } 292 catch (NoSuchAlgorithmException e) 293 { 294 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 295 } 296 } 297 298 MessageDigest createDigest(ASN1ObjectIdentifier algorithm) 299 throws CRMFException 300 { 301 try 302 { 303 String digestName = (String)DIGEST_ALG_NAMES.get(algorithm); 304 305 if (digestName != null) 306 { 307 try 308 { 309 // this is reversed as the Sun policy files now allow unlimited strength RSA 310 return helper.createDigest(digestName); 311 } 312 catch (NoSuchAlgorithmException e) 313 { 314 // Ignore 315 } 316 } 317 return helper.createDigest(algorithm.getId()); 318 } 319 catch (NoSuchAlgorithmException e) 320 { 321 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 322 } 323 catch (NoSuchProviderException e) 324 { 325 throw new CRMFException("cannot create cipher: " + e.getMessage(), e); 326 } 327 } 328 329 Mac createMac(ASN1ObjectIdentifier algorithm) 330 throws CRMFException 331 { 332 try 333 { 334 String macName = (String)MAC_ALG_NAMES.get(algorithm); 335 336 if (macName != null) 337 { 338 try 339 { 340 // this is reversed as the Sun policy files now allow unlimited strength RSA 341 return helper.createMac(macName); 342 } 343 catch (NoSuchAlgorithmException e) 344 { 345 // Ignore 346 } 347 } 348 return helper.createMac(algorithm.getId()); 349 } 350 catch (NoSuchProviderException e) 351 { 352 throw new CRMFException("cannot create mac: " + e.getMessage(), e); 353 } 354 catch (NoSuchAlgorithmException e) 355 { 356 throw new CRMFException("cannot create mac: " + e.getMessage(), e); 357 } 358 } 359 360 AlgorithmParameterGenerator createAlgorithmParameterGenerator(ASN1ObjectIdentifier algorithm) 361 throws GeneralSecurityException 362 { 363 String algorithmName = (String)BASE_CIPHER_NAMES.get(algorithm); 364 365 try 366 { 367 if (algorithmName != null) 368 { 369 try 370 { 371 // this is reversed as the Sun policy files now allow unlimited strength RSA 372 return helper.createAlgorithmParameterGenerator(algorithmName); 373 } 374 catch (NoSuchAlgorithmException e) 375 { 376 // Ignore 377 } 378 } 379 return helper.createAlgorithmParameterGenerator(algorithm.getId()); 380 } 381 catch (NoSuchAlgorithmException e) 382 { 383 throw new GeneralSecurityException(e.toString()); 384 } 385 catch (NoSuchProviderException e) 386 { 387 throw new GeneralSecurityException(e.toString()); 388 } 389 } 390 391 AlgorithmParameters generateParameters(ASN1ObjectIdentifier encryptionOID, SecretKey encKey, SecureRandom rand) 392 throws CRMFException 393 { 394 try 395 { 396 AlgorithmParameterGenerator pGen = createAlgorithmParameterGenerator(encryptionOID); 397 398 if (encryptionOID.equals(CMSEnvelopedDataGenerator.RC2_CBC)) 399 { 400 byte[] iv = new byte[8]; 401 402 rand.nextBytes(iv); 403 404 try 405 { 406 pGen.init(new RC2ParameterSpec(encKey.getEncoded().length * 8, iv), rand); 407 } 408 catch (InvalidAlgorithmParameterException e) 409 { 410 throw new CRMFException("parameters generation error: " + e, e); 411 } 412 } 413 414 return pGen.generateParameters(); 415 } 416 catch (GeneralSecurityException e) 417 { 418 throw new CRMFException("exception creating algorithm parameter generator: " + e, e); 419 } 420 } 421 422 AlgorithmIdentifier getAlgorithmIdentifier(ASN1ObjectIdentifier encryptionOID, AlgorithmParameters params) 423 throws CRMFException 424 { 425 ASN1Encodable asn1Params; 426 if (params != null) 427 { 428 try 429 { 430 asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1")); 431 } 432 catch (IOException e) 433 { 434 throw new CRMFException("cannot encode parameters: " + e.getMessage(), e); 435 } 436 } 437 else 438 { 439 asn1Params = DERNull.INSTANCE; 440 } 441 442 return new AlgorithmIdentifier( 443 encryptionOID, 444 asn1Params); 445 } 446 447 static Object execute(JCECallback callback) throws CRMFException 448 { 449 try 450 { 451 return callback.doInJCE(); 452 } 453 catch (NoSuchAlgorithmException e) 454 { 455 throw new CRMFException("can't find algorithm.", e); 456 } 457 catch (InvalidKeyException e) 458 { 459 throw new CRMFException("key invalid in message.", e); 460 } 461 catch (NoSuchProviderException e) 462 { 463 throw new CRMFException("can't find provider.", e); 464 } 465 catch (NoSuchPaddingException e) 466 { 467 throw new CRMFException("required padding not supported.", e); 468 } 469 catch (InvalidAlgorithmParameterException e) 470 { 471 throw new CRMFException("algorithm parameters invalid.", e); 472 } 473 catch (InvalidParameterSpecException e) 474 { 475 throw new CRMFException("MAC algorithm parameter spec invalid.", e); 476 } 477 } 478 479 static interface JCECallback 480 { 481 Object doInJCE() 482 throws CRMFException, InvalidAlgorithmParameterException, InvalidKeyException, InvalidParameterSpecException, 483 NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException; 484 } 485 } 486