001/* 002 * Copyright 2022-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2022-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2022-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.util.ssl.cert; 037 038 039 040import java.util.Collections; 041import java.util.HashSet; 042import java.util.Map; 043import java.util.Set; 044 045import com.unboundid.util.NotNull; 046import com.unboundid.util.Nullable; 047import com.unboundid.util.OID; 048import com.unboundid.util.ObjectPair; 049import com.unboundid.util.StaticUtils; 050import com.unboundid.util.ThreadSafety; 051import com.unboundid.util.ThreadSafetyLevel; 052 053import static com.unboundid.util.ssl.cert.CertMessages.*; 054 055 056 057/** 058 * This enum defines a set of OIDs and algorithm names for password-based 059 * cryptography as described in the PKCS #5 specification defined in RFC 8018. 060 */ 061@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 062public enum PKCS5AlgorithmIdentifier 063{ 064 /** 065 * The algorithm identifier for the PBES2 encryption scheme. This scheme is 066 * defined in RFC 8018 section 6.2, and the identifier is defined in appendix 067 * A.4 of that specification. 068 */ 069 PBES2("1.2.840.113549.1.5.13", "PBES2", Collections.<String>emptySet(), 070 INFO_PKCS5_ALG_ID_DESC_PBES2.get()), 071 072 073 074 /** 075 * The algorithm identifier for the PBKDF2 key derivation function, which is 076 * intended to be used by the PBES2 encryption scheme. This identifier is 077 * described in RFC 8018 appendix A.2. 078 */ 079 PBKDF2("1.2.840.113549.1.5.12", "PBKDF2", Collections.<String>emptySet(), 080 INFO_PKCS5_ALG_ID_DESC_PBKDF2.get()), 081 082 083 084 /** 085 * The algorithm identifier for the HMAC-SHA-1 pseudorandom function, which 086 * may be used in conjunction with the PBKDF2 key derivation function. This 087 * identifier is described in RFC 8018 appendix B.1.1. 088 */ 089 HMAC_SHA_1("1.2.840.113549.2.7", "HMAC-SHA-1", 090 StaticUtils.setOf("HMAC-SHA", "HmacSHA"), 091 INFO_PKCS5_ALG_ID_DESC_HMAC_SHA_1.get()), 092 093 094 095 /** 096 * The algorithm identifier for the HMAC-SHA-224 pseudorandom function, which 097 * may be used in conjunction with the PBKDF2 key derivation function. This 098 * identifier is described in RFC 8018 appendix B.1.2. 099 */ 100 HMAC_SHA_224("1.2.840.113549.2.8", "HMAC-SHA-224", 101 StaticUtils.setOf("HmacSHA224"), 102 INFO_PKCS5_ALG_ID_DESC_HMAC_SHA_224.get()), 103 104 105 106 /** 107 * The algorithm identifier for the HMAC-SHA-256 pseudorandom function, which 108 * may be used in conjunction with the PBKDF2 key derivation function. This 109 * identifier is described in RFC 8018 appendix B.1.2. 110 */ 111 HMAC_SHA_256("1.2.840.113549.2.9", "HMAC-SHA-256", 112 StaticUtils.setOf("HmacSHA256"), 113 INFO_PKCS5_ALG_ID_DESC_HMAC_SHA_256.get()), 114 115 116 117 /** 118 * The algorithm identifier for the HMAC-SHA-384 pseudorandom function, which 119 * may be used in conjunction with the PBKDF2 key derivation function. This 120 * identifier is described in RFC 8018 appendix B.1.2. 121 */ 122 HMAC_SHA_384("1.2.840.113549.2.10", "HMAC-SHA-384", 123 StaticUtils.setOf("HmacSHA384"), 124 INFO_PKCS5_ALG_ID_DESC_HMAC_SHA_384.get()), 125 126 127 128 /** 129 * The algorithm identifier for the HMAC-SHA-512 pseudorandom function, which 130 * may be used in conjunction with the PBKDF2 key derivation function. This 131 * identifier is described in RFC 8018 appendix B.1.2. 132 */ 133 HMAC_SHA_512("1.2.840.113549.2.11", "HMAC-SHA-512", 134 StaticUtils.setOf("HmacSHA512"), 135 INFO_PKCS5_ALG_ID_DESC_HMAC_SHA_512.get()), 136 137 138 139 /** 140 * The algorithm identifier for the DESede/CBC/PKCS5Padding cipher 141 * transformation. This identifier is described in RFC 8018 appendix B.2.2. 142 */ 143 DES_EDE3_CBC_PAD("1.2.840.113549.3.7", "DES-EDE3-CBC-PAD", 144 StaticUtils.setOf("DES-EDE-CBC-PAD", "DES-EDE3-CBC", "DES-EDE-CBC", 145 "DES-EDE3", "DESEDE3", "DES-EDE", "DESEDE", 146 "3DES-CBC-PAD", "3DES-CBC", "3DES"), 147 INFO_PKCS5_ALG_ID_DESC_DES_EDE_CBC_PAD.get()), 148 149 150 151 /** 152 * The algorithm identifier for the 128-bit AES/CBC/PKCS5Padding cipher 153 * transformation. This identifier is described in RFC 8018 appendix B.2.2. 154 */ 155 AES_128_CBC_PAD("2.16.840.1.101.3.4.1.2", "AES-128-CBC-PAD", 156 StaticUtils.setOf("AES128-CBC", "AES128", "AES", 157 "AES/CBC/PKCS5Padding", "AES128/CBC/PKCS5Padding"), 158 INFO_PKCS5_ALG_ID_DESC_AES_128_CBC_PAD.get()), 159 160 161 162 /** 163 * The algorithm identifier for the 192-bit AES/CBC/PKCS5Padding cipher 164 * transformation. This identifier is described in RFC 8018 appendix C. 165 */ 166 AES_192_CBC_PAD("2.16.840.1.101.3.4.1.22", "AES-192-CBC-PAD", 167 StaticUtils.setOf("AES192-CBC", "AES192", "AES192/CBC/PKCS5Padding"), 168 INFO_PKCS5_ALG_ID_DESC_AES_192_CBC_PAD.get()), 169 170 171 172 /** 173 * The algorithm identifier for the 256-bit AES/CBC/PKCS5Padding cipher 174 * transformation. This identifier is described in RFC 8018 appendix C. 175 */ 176 AES_256_CBC_PAD("2.16.840.1.101.3.4.1.42", "AES-256-CBC-PAD", 177 StaticUtils.setOf("AES256-CBC", "AES256", "AES256/CBC/PKCS5Padding"), 178 INFO_PKCS5_ALG_ID_DESC_AES_256_CBC_PAD.get()); 179 180 181 182 /** 183 * Retrieve a map of pseudorandom functions defined in this set of PKCS #5 184 * algorithm identifiers. The value for each item in the map will be the 185 * name of the secret key factory algorithm that corresponds to the PBKDF2 186 * variant that uses the specified function. 187 */ 188 @NotNull private static final Map<PKCS5AlgorithmIdentifier,String> 189 PSEUDORANDOM_FUNCTIONS = StaticUtils.mapOf( 190 HMAC_SHA_1, "PBKDF2WithHmacSHA1", 191 HMAC_SHA_224, "PBKDF2WithHmacSHA224", 192 HMAC_SHA_256, "PBKDF2WithHmacSHA256", 193 HMAC_SHA_384, "PBKDF2WithHmacSHA384", 194 HMAC_SHA_512, "PBKDF2WithHmacSHA512"); 195 196 197 198 /** 199 * A map of information about cipher transformations defined in this set of 200 * PKCS #5 algorithm identifiers. The value for each item in the map is an 201 * object pair in which the first element is the name of the cipher 202 * transformation and the second element is the expected key size, in bits. 203 */ 204 @NotNull() 205 private static final Map<PKCS5AlgorithmIdentifier,ObjectPair<String,Integer>> 206 CIPHER_TRANSFORMATIONS = StaticUtils.mapOf( 207 DES_EDE3_CBC_PAD, new ObjectPair<>("DESede/CBC/PKCS5Padding", 192), 208 AES_128_CBC_PAD, new ObjectPair<>("AES/CBC/PKCS5Padding", 128), 209 AES_192_CBC_PAD, new ObjectPair<>("AES/CBC/PKCS5Padding", 192), 210 AES_256_CBC_PAD, new ObjectPair<>("AES/CBC/PKCS5Padding", 256)); 211 212 213 214 // The OID for this identifier. 215 @NotNull private final OID oid; 216 217 // A set of prepared names that may be used to reference this algorithm 218 // identifier. 219 @NotNull private final Set<String> preparedNames; 220 221 // A human-readable description for the associated algorithm. 222 @NotNull private final String description; 223 224 // The primary name for the associated algorithm. 225 @NotNull private final String primaryName; 226 227 228 229 /** 230 * Creates a new PKCS #5 algorithm identifier with the provided information. 231 * 232 * @param oidString The string representation of the OID for this 233 * algorithm identifier. It must not be 234 * {@code null} and must represent a valid OID. 235 * @param primaryName The primary name for this algorithm identifier. 236 * It must not be {@code null}. 237 * @param alternativeNames A set of alternative names for this algorithm 238 * identifier. It must not be {@code null}, but may 239 * be empty. 240 * @param description A human-readable description for the associated 241 * algorithm. 242 */ 243 PKCS5AlgorithmIdentifier(@NotNull final String oidString, 244 @NotNull final String primaryName, 245 @NotNull final Set<String> alternativeNames, 246 @NotNull final String description) 247 { 248 this.primaryName = primaryName; 249 this.description = description; 250 251 final Set<String> preparedNameSet = new HashSet<>(); 252 preparedNameSet.add(prepareName(primaryName)); 253 for (final String alternativeName : alternativeNames) 254 { 255 preparedNameSet.add(prepareName(alternativeName)); 256 } 257 258 preparedNames = Collections.unmodifiableSet(preparedNameSet); 259 260 oid = new OID(oidString); 261 } 262 263 264 265 /** 266 * Retrieves the OID for this PKCS #5 algorithm identifier. 267 * 268 * @return The OID for this PKCS #5 algorithm identifier. 269 */ 270 @NotNull() 271 public OID getOID() 272 { 273 return oid; 274 } 275 276 277 278 /** 279 * Retrieves the name for the algorithm. 280 * 281 * @return The name for the algorithm. 282 */ 283 @NotNull() 284 public String getName() 285 { 286 return primaryName; 287 } 288 289 290 291 /** 292 * Retrieves a human-readable description for the algorithm. 293 * 294 * @return A human-readable description for the algorithm. 295 */ 296 @NotNull() 297 public String getDescription() 298 { 299 return description; 300 } 301 302 303 304 /** 305 * Retrieves the PKCS #5 algorithm identifier with the specified OID. 306 * 307 * @param oid The OID for the PKCS #5 algorithm identifier instance to 308 * retrieve. It must not be {@code null}. 309 * 310 * @return The appropriate PKCS #5 algorithm identifier instance, or 311 * {@code null} if the provided OID does not reference a known PKCS 312 * #5 algorithm identifier. 313 */ 314 @Nullable() 315 public static PKCS5AlgorithmIdentifier forOID(@NotNull final OID oid) 316 { 317 for (final PKCS5AlgorithmIdentifier v : values()) 318 { 319 if (v.oid.equals(oid)) 320 { 321 return v; 322 } 323 } 324 325 return null; 326 } 327 328 329 330 /** 331 * Retrieves the PKCS #5 algorithm identifier with the specified name. 332 * 333 * @param name The name for the PKCS #5 algorithm identifier to retrieve. 334 * It must not be {@code null}. 335 * 336 * @return The appropriate PKCS #5 algorithm identifier instance, or 337 * {@code null} if the provided name does not reference a known PKCS 338 * #5 algorithm identifier. 339 */ 340 @Nullable() 341 public static PKCS5AlgorithmIdentifier forName(@NotNull final String name) 342 { 343 final String preparedName = prepareName(name); 344 for (final PKCS5AlgorithmIdentifier v : values()) 345 { 346 if (v.preparedNames.contains(preparedName)) 347 { 348 return v; 349 } 350 } 351 352 return null; 353 } 354 355 356 357 /** 358 * Prepares the provided name to be used by the {@link #forName(String)} 359 * method. All spaces, dashes, underscores, and forward slashes will be 360 * removed. 361 * 362 * @param name The name to be compared. 363 * 364 * @return The prepared version of the provided name. 365 */ 366 @NotNull() 367 private static String prepareName(@NotNull final String name) 368 { 369 final StringBuilder buffer = new StringBuilder(name.length()); 370 371 for (final char c : name.toLowerCase().toCharArray()) 372 { 373 switch (c) 374 { 375 case ' ': 376 case '-': 377 case '_': 378 case '/': 379 // This character will be omitted. 380 break; 381 default: 382 // This character will be used. 383 buffer.append(c); 384 } 385 } 386 387 return buffer.toString(); 388 } 389 390 391 392 /** 393 * Retrieves the human-readable name for the PKCS #5 algorithm identifier 394 * value with the provided OID, or a string representation of the OID if there 395 * is no value with that OID. 396 * 397 * @param oid The OID for the PKCS #5 algorithm identifier to retrieve. 398 * 399 * @return The human-readable name for the PKCS #5 algorithm identifier value 400 * with the provided OID, or a string representation of the OID if 401 * there is no value with that OID. 402 */ 403 @NotNull() 404 public static String getNameOrOID(@NotNull final OID oid) 405 { 406 final PKCS5AlgorithmIdentifier id = forOID(oid); 407 if (id == null) 408 { 409 return oid.toString(); 410 } 411 else 412 { 413 return id.primaryName; 414 } 415 } 416 417 418 419 /** 420 * Retrieves the set of PKCS #5 algorithm identifiers that represent 421 * pseudorandom functions. 422 * 423 * @return The set of PKCS #5 algorithm identifiers that represent 424 * pseudorandom functions. 425 */ 426 @NotNull() 427 public static Set<PKCS5AlgorithmIdentifier> getPseudorandomFunctions() 428 { 429 return PSEUDORANDOM_FUNCTIONS.keySet(); 430 } 431 432 433 434 /** 435 * Retrieves the name of the secret key factory algorithm that should be used 436 * to create a PBKDF2 key factory that uses the specified pseudorandom 437 * function. 438 * 439 * @param identifier The PKCS #5 algorithm identifier that represents the 440 * pseudorandom function for which to obtain the name of 441 * the corresponding PBKDF2 secret key factory algorithm. 442 * It must not be {@code null}. 443 * 444 * @return The name of the PBKDF2 key factory algorithm that uses the 445 * specified pseudorandom function, or {@code null} if the provided 446 * identifier does not represent a known pseudorandom function. 447 */ 448 @Nullable() 449 public static String 450 getPBKDF2SecretKeyFactoryAlgorithmForPseudorandomFunction( 451 @NotNull final PKCS5AlgorithmIdentifier identifier) 452 { 453 return PSEUDORANDOM_FUNCTIONS.get(identifier); 454 } 455 456 457 458 /** 459 * Retrieves the set of PKCS #5 algorithm identifiers that represent cipher 460 * transformations. 461 * 462 * @return The set of PKCS #5 algorithm identifiers that represent cipher 463 * transformations. 464 */ 465 @NotNull() 466 public static Set<PKCS5AlgorithmIdentifier> getCipherTransformations() 467 { 468 return CIPHER_TRANSFORMATIONS.keySet(); 469 } 470 471 472 473 /** 474 * Retrieves the name of the cipher algorithm that should be used when 475 * creating a secret key for the specified cipher transformation. 476 * 477 * @param identifier The PKCS #5 algorithm identifier that represents the 478 * cipher transformation for which to obtain the name of 479 * the corresponding cipher algorithm. It must not be 480 * {@code null}. 481 * 482 * @return The name of the cipher algorithm that should be used when creating 483 * a secret key for the specified cipher transformation, or 484 * {@code null} if the provided identifier does not represent a known 485 * cipher transformation. 486 */ 487 @Nullable() 488 public static String getCipherAlgorithmName( 489 @NotNull final PKCS5AlgorithmIdentifier identifier) 490 { 491 final ObjectPair<String,Integer> cipherTransformationPair = 492 CIPHER_TRANSFORMATIONS.get(identifier); 493 if (cipherTransformationPair == null) 494 { 495 return null; 496 } 497 498 final String cipherTransformationName = cipherTransformationPair.getFirst(); 499 final int slashPos = cipherTransformationName.indexOf('/'); 500 return cipherTransformationName.substring(0, slashPos); 501 } 502 503 504 505 /** 506 * Retrieves the name of the cipher transformation that should be used when 507 * creating a cipher instance for the specified cipher transformation. 508 * 509 * @param identifier The PKCS #5 algorithm identifier that represents the 510 * cipher transformation for which to obtain the name. It 511 * must not be {@code null}. 512 * 513 * @return The name of the cipher transformation that should be used when 514 * creating a cipher instance for the specified cipher 515 * transformation, or {@code null} if the provided identifier does 516 * not represent a known cipher transformation. 517 */ 518 @Nullable() 519 public static String getCipherTransformationName( 520 @NotNull final PKCS5AlgorithmIdentifier identifier) 521 { 522 final ObjectPair<String,Integer> cipherTransformationPair = 523 CIPHER_TRANSFORMATIONS.get(identifier); 524 if (cipherTransformationPair == null) 525 { 526 return null; 527 } 528 529 return cipherTransformationPair.getFirst(); 530 } 531 532 533 534 /** 535 * Retrieves the key size, in bits, that should be used when creating a 536 * secret key for the specified cipher transformation. 537 * 538 * @param identifier The PKCS #5 algorithm identifier that represents the 539 * cipher transformation for which to obtain the key size. 540 * It must not be {@code null}. 541 * 542 * @return The key size, in bits, that should be used when creating a secret 543 * key for the specified cipher transformation, or {@code null} if 544 * the provided identifier does not represent a known cipher 545 * transformation. 546 */ 547 @Nullable() 548 public static Integer getCipherKeySizeBits( 549 @NotNull final PKCS5AlgorithmIdentifier identifier) 550 { 551 final ObjectPair<String,Integer> cipherTransformationPair = 552 CIPHER_TRANSFORMATIONS.get(identifier); 553 if (cipherTransformationPair == null) 554 { 555 return null; 556 } 557 558 return cipherTransformationPair.getSecond(); 559 } 560 561 562 563 /** 564 * Retrieves a string representation of this PKCS #5 algorithm identifier. 565 * 566 * @return A string representation of this PKCS #5 algorithm identifier. 567 */ 568 @Override() 569 @NotNull() 570 public String toString() 571 { 572 return primaryName; 573 } 574}