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