001/* 002 * Copyright 2020-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2020-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) 2020-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; 037 038 039 040import java.util.concurrent.atomic.AtomicReference; 041import javax.crypto.Cipher; 042 043 044 045/** 046 * This enum defines sets of settings that may be used when encrypting data with 047 * a {@link PassphraseEncryptedOutputStream}. 048 */ 049@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 050public enum PassphraseEncryptionCipherType 051{ 052 /** 053 * Cipher settings that use a 128-bit AES cipher. 054 */ 055 AES_128("AES/CBC/PKCS5Padding", 128, "PBKDF2WithHmacSHA1", 056 PassphraseEncryptedOutputStream. 057 DEFAULT_AES_128_CIPHER_TYPE_ITERATION_COUNT, 058 16, 16, "HmacSHA256"), 059 060 061 062 /** 063 * Cipher settings that use a 256-bit AES cipher. 064 */ 065 AES_256("AES/CBC/PKCS5Padding", 256, "PBKDF2WithHmacSHA512", 066 PassphraseEncryptedOutputStream. 067 DEFAULT_AES_256_CIPHER_TYPE_ITERATION_COUNT, 068 16, 16, "HmacSHA512"); 069 070 071 072 /** 073 * A reference to the strongest defined cipher type value that is supported by 074 * the underlying JVM. Its value will be {@code null} until the first attempt 075 * is made to determine it. The cached value will be used for subsequent 076 * attempts to retrieve the value. 077 */ 078 @NotNull private static final AtomicReference<PassphraseEncryptionCipherType> 079 STRONGEST_AVAILABLE_CIPHER_TYPE = new AtomicReference<>(); 080 081 082 083 // The length (in bytes) to use for the initialization vector when creating 084 // the cipher. 085 private final int initializationVectorLengthBytes; 086 087 // The iteration count that will be used when generating the encryption key 088 // from the passphrase. 089 private final int keyFactoryIterationCount; 090 091 // The length (in bytes) to use for the salt when generating the encryption 092 // key from the passphrase. 093 private final int keyFactorySaltLengthBytes; 094 095 // The length (in bits) for the encryption key to generate from the 096 // passphrase. 097 private final int keyLengthBits; 098 099 // The cipher transformation that will be used for the encryption. 100 @NotNull private final String cipherTransformation; 101 102 // The name of the algorithm that will be used to generate the encryption key 103 // from the passphrase. 104 @NotNull private final String keyFactoryAlgorithm; 105 106 // The name of the algorithm that will be used to generate a MAC of the 107 // encryption header contents. 108 @NotNull private final String macAlgorithm; 109 110 111 112 /** 113 * Creates a new passphrase encryption cipher type value with the provided 114 * information. 115 * 116 * @param cipherTransformation 117 * The cipher transformation that will be used for the 118 * encryption. 119 * @param keyLengthBits 120 * The length (in bits) for the encryption key to generate. 121 * @param keyFactoryAlgorithm 122 * The name of the algorithm that will be used to generate the 123 * encryption key from the passphrase. 124 * @param keyFactoryIterationCount 125 * The iteration count that will be used when generating the 126 * encryption key from the passphrase. 127 * @param keyFactorySaltLengthBytes 128 * The length (in bytes) to use for the salt when generating the 129 * encryption key from the passphrase. 130 * @param initializationVectorLengthBytes 131 * The length (in bytes) to use for the initialization vector 132 * when creating the cipher. 133 * @param macAlgorithm 134 * The name of the algorithm that will be used to generate a MAC 135 * of the encryption header contents. 136 */ 137 PassphraseEncryptionCipherType(@NotNull final String cipherTransformation, 138 final int keyLengthBits, 139 @NotNull final String keyFactoryAlgorithm, 140 final int keyFactoryIterationCount, 141 final int keyFactorySaltLengthBytes, 142 final int initializationVectorLengthBytes, 143 @NotNull final String macAlgorithm) 144 { 145 this.cipherTransformation = cipherTransformation; 146 this.keyLengthBits = keyLengthBits; 147 this.keyFactoryAlgorithm = keyFactoryAlgorithm; 148 this.keyFactoryIterationCount = keyFactoryIterationCount; 149 this.keyFactorySaltLengthBytes = keyFactorySaltLengthBytes; 150 this.initializationVectorLengthBytes = initializationVectorLengthBytes; 151 this.macAlgorithm = macAlgorithm; 152 } 153 154 155 156 /** 157 * Retrieves the cipher transformation that will be used for the encryption. 158 * 159 * @return The cipher transformation that will be used for the encryption. 160 */ 161 @NotNull() 162 public String getCipherTransformation() 163 { 164 return cipherTransformation; 165 } 166 167 168 169 /** 170 * Retrieves the length (in bits) for the encryption key to generate. 171 * 172 * @return The length (in bits) for the encryption key to generate. 173 */ 174 public int getKeyLengthBits() 175 { 176 return keyLengthBits; 177 } 178 179 180 181 /** 182 * Retrieves the name of the algorithm that will be used to generate the 183 * encryption key from the passphrase. 184 * 185 * @return The name of the algorithm that will be used to generate the 186 * encryption key from the passphrase. 187 */ 188 @NotNull() 189 public String getKeyFactoryAlgorithm() 190 { 191 return keyFactoryAlgorithm; 192 } 193 194 195 196 /** 197 * Retrieves the iteration count that will be used when generating the 198 * encryption key from the passphrase. 199 * 200 * @return The iteration count that will be used when generating the 201 * encryption key from the passphrase. 202 */ 203 public int getKeyFactoryIterationCount() 204 { 205 return keyFactoryIterationCount; 206 } 207 208 209 210 /** 211 * Retrieves the length (in bytes) to use for the salt when generating the 212 * encryption key from the passphrase. 213 * 214 * @return The length (in bytes) to use for the salt when generating the 215 * encryption key from the passphrase. 216 */ 217 public int getKeyFactorySaltLengthBytes() 218 { 219 return keyFactorySaltLengthBytes; 220 } 221 222 223 224 /** 225 * Retrieves the length (in bytes) to use for the initialization vector when 226 * generating the cipher. 227 * 228 * @return The length (in bytes) to use for the initialization vector when 229 * generating the cipher. 230 */ 231 public int getInitializationVectorLengthBytes() 232 { 233 return initializationVectorLengthBytes; 234 } 235 236 237 238 /** 239 * Retrieves the name of the algorithm that will be used to generate a MAC of 240 * the encryption header contents. 241 * 242 * @return The name of the algorithm that will be used to generate a MAC of 243 * the encryption header contents. 244 */ 245 @NotNull() 246 public String getMacAlgorithm() 247 { 248 return macAlgorithm; 249 } 250 251 252 253 /** 254 * Retrieves the cipher type value for the provided name. 255 * 256 * @param name The name of the cipher type value to retrieve. 257 * 258 * @return The cipher type object for the given name, or {@code null} if the 259 * provided name does not map to any cipher type value. 260 */ 261 @Nullable() 262 public static PassphraseEncryptionCipherType forName( 263 @NotNull final String name) 264 { 265 final String transformedName = 266 StaticUtils.toUpperCase(name).replace('-', '_'); 267 for (final PassphraseEncryptionCipherType value : values()) 268 { 269 if (value.name().equals(transformedName)) 270 { 271 return value; 272 } 273 } 274 275 return null; 276 } 277 278 279 280 /** 281 * Retrieves the cipher type value that corresponds to the strongest supported 282 * level of protection that is available in the underlying JVM. 283 * 284 * @return The cipher type value that corresponds to the strongest supported 285 * level of protection in the underlying JVM. 286 */ 287 @NotNull() 288 public static PassphraseEncryptionCipherType getStrongestAvailableCipherType() 289 { 290 PassphraseEncryptionCipherType cipherType = 291 STRONGEST_AVAILABLE_CIPHER_TYPE.get(); 292 if (cipherType == null) 293 { 294 cipherType = PassphraseEncryptionCipherType.AES_128; 295 296 try 297 { 298 final PassphraseEncryptionCipherType ct = 299 PassphraseEncryptionCipherType.AES_256; 300 final PassphraseEncryptedStreamHeader header = 301 new PassphraseEncryptedStreamHeader( 302 "dummy-passphrase".toCharArray(), ct.getKeyFactoryAlgorithm(), 303 ct.getKeyFactoryIterationCount(), 304 new byte[ct.getKeyFactorySaltLengthBytes()], 305 ct.getKeyLengthBits(), ct.getCipherTransformation(), 306 new byte[ct.getInitializationVectorLengthBytes()], 307 null, ct.getMacAlgorithm()); 308 header.createCipher(Cipher.ENCRYPT_MODE); 309 cipherType = ct; 310 } 311 catch (final Exception e) 312 { 313 Debug.debugException(e); 314 } 315 316 if (! STRONGEST_AVAILABLE_CIPHER_TYPE.compareAndSet(null, cipherType)) 317 { 318 cipherType = STRONGEST_AVAILABLE_CIPHER_TYPE.get(); 319 } 320 } 321 322 return cipherType; 323 } 324 325 326 327 /** 328 * Retrieves a string representation of this cipher type value. 329 * 330 * @return A string representation of this cipher type value. 331 */ 332 @Override() 333 @NotNull() 334 public String toString() 335 { 336 final StringBuilder buffer = new StringBuilder(); 337 toString(buffer); 338 return buffer.toString(); 339 } 340 341 342 343 /** 344 * Appends a string representation of this cipher type value to the provided 345 * buffer. 346 * 347 * @param buffer The buffer to which the information should be appended. 348 */ 349 public void toString(@NotNull final StringBuilder buffer) 350 { 351 buffer.append("PassphraseEncryptedCipherType(cipherTransformation='"); 352 buffer.append(cipherTransformation); 353 buffer.append("', keyLengthBits="); 354 buffer.append(keyLengthBits); 355 buffer.append(", keyFactoryAlgorithm='"); 356 buffer.append(keyFactoryAlgorithm); 357 buffer.append("', keyFactoryIterationCount="); 358 buffer.append(keyFactoryIterationCount); 359 buffer.append(", keyFactorySaltLengthBytes="); 360 buffer.append(keyFactorySaltLengthBytes); 361 buffer.append(", initializationVectorLengthBytes="); 362 buffer.append(initializationVectorLengthBytes); 363 buffer.append(", macAlgorithm='"); 364 buffer.append(macAlgorithm); 365 buffer.append("')"); 366 } 367}