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.io.Serializable; 041 042import com.unboundid.util.Mutable; 043import com.unboundid.util.NotNull; 044import com.unboundid.util.ThreadSafety; 045import com.unboundid.util.ThreadSafetyLevel; 046import com.unboundid.util.Validator; 047 048import static com.unboundid.util.ssl.cert.CertMessages.*; 049 050 051 052/** 053 * This class defines a set of properties that may be used when encrypting a 054 * PKCS #8 private key. 055 */ 056@Mutable() 057@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 058public final class PKCS8EncryptionProperties 059 implements Serializable 060{ 061 /** 062 * The default value that will be used for the key factory iteration count. 063 */ 064 private static final int DEFAULT_KEY_FACTORY_ITERATION_COUNT = 2048; 065 066 067 068 /** 069 * The default value that will be used for the key factory salt length. 070 */ 071 private static final int DEFAULT_KEY_FACTORY_SALT_LENGTH_BYTES = 8; 072 073 074 075 /** 076 * The default value that will be used for the encryption cipher 077 * transformation. 078 */ 079 @NotNull() 080 private static final PKCS5AlgorithmIdentifier DEFAULT_CIPHER_TRANSFORMATION = 081 PKCS5AlgorithmIdentifier.AES_128_CBC_PAD; 082 083 084 085 /** 086 * The default value that will be used for the pseudorandom function for the 087 * key factory algorithm. 088 */ 089 @NotNull() 090 private static final PKCS5AlgorithmIdentifier DEFAULT_KEY_FACTORY_PRF = 091 PKCS5AlgorithmIdentifier.HMAC_SHA_256; 092 093 094 095 /** 096 * The serial version UID for this serializable class. 097 */ 098 private static final long serialVersionUID = 9162621645150582722L; 099 100 101 102 // The iteration count to use when generating the encryption key from the 103 // encryption password. 104 private int keyFactoryIterationCount; 105 106 // The length of the key factory salt to create, in bytes. 107 private int keyFactorySaltLengthBytes; 108 109 // The cipher transformation to use to encrypt the private key. 110 @NotNull private PKCS5AlgorithmIdentifier cipherTransformationAlgorithm; 111 112 // The algorithm to use to generate the encryption key from the encryption 113 // password. 114 @NotNull private PKCS5AlgorithmIdentifier keyFactoryPRFAlgorithm; 115 116 117 118 /** 119 * Creates a set of PKCS #8 encryption properties with the default settings. 120 */ 121 public PKCS8EncryptionProperties() 122 { 123 keyFactoryIterationCount = DEFAULT_KEY_FACTORY_ITERATION_COUNT; 124 keyFactorySaltLengthBytes = DEFAULT_KEY_FACTORY_SALT_LENGTH_BYTES; 125 cipherTransformationAlgorithm = DEFAULT_CIPHER_TRANSFORMATION; 126 keyFactoryPRFAlgorithm = DEFAULT_KEY_FACTORY_PRF; 127 } 128 129 130 131 /** 132 * Retrieves the algorithm identifier for the pseudorandom function to use for 133 * the key factory when generating the encryption key from the provided 134 * password. 135 * 136 * @return The algorithm identifier for the pseudorandom function to use for 137 * the key factory when generating the encryption key from the 138 * provided password. 139 */ 140 @NotNull() 141 public PKCS5AlgorithmIdentifier getKeyFactoryPRFAlgorithm() 142 { 143 return keyFactoryPRFAlgorithm; 144 } 145 146 147 148 /** 149 * Specifies the algorithm identifier for the pseudorandom function to use 150 * when generating the encryption key from the provided password. 151 * 152 * @param keyFactoryPRFAlgorithm The algorithm identifier for the 153 * pseudorandom function to use when 154 * generating the encryption key from the 155 * provided password. It must not be 156 * {@code null}, and it must represent a valid 157 * pseudorandom function. 158 * 159 * @throws CertException If the provided algorithm identifier does not 160 * represent a valid pseudorandom function. 161 */ 162 public void setKeyFactoryPRFAlgorithm( 163 @NotNull final PKCS5AlgorithmIdentifier keyFactoryPRFAlgorithm) 164 throws CertException 165 { 166 if (! PKCS5AlgorithmIdentifier.getPseudorandomFunctions().contains( 167 keyFactoryPRFAlgorithm)) 168 { 169 throw new CertException( 170 ERR_PKCS8_ENC_PROPS_INVALID_KEY_FACTORY_PRF_ALG.get( 171 keyFactoryPRFAlgorithm.getName(), 172 keyFactoryPRFAlgorithm.getDescription())); 173 } 174 175 this.keyFactoryPRFAlgorithm = keyFactoryPRFAlgorithm; 176 } 177 178 179 180 /** 181 * Retrieves the iteration count to use when generating the encryption key 182 * from the provided password. 183 * 184 * @return The iteration count to use when generating the encryption key from 185 * the provided password. 186 */ 187 public int getKeyFactoryIterationCount() 188 { 189 return keyFactoryIterationCount; 190 } 191 192 193 194 /** 195 * Specifies the iteration count to use when generating the encryption key 196 * from the provided password. 197 * 198 * @param keyFactoryIterationCount The iteration count to use when 199 * generating the encryption key from the 200 * provided password. It must be greater 201 * than zero. 202 */ 203 public void setKeyFactoryIterationCount(final int keyFactoryIterationCount) 204 { 205 Validator.ensureTrue((keyFactoryIterationCount > 0), 206 "The key factory iteration count must be greater than zero."); 207 this.keyFactoryIterationCount = keyFactoryIterationCount; 208 } 209 210 211 212 /** 213 * Retrieves the length in bytes to use for the key factory salt when 214 * generating the encryption key from the provided password. 215 * 216 * @return The length in bytes to use for the key factory salt when 217 * generating the encryption key from the provided password. 218 */ 219 public int getKeyFactorySaltLengthBytes() 220 { 221 return keyFactorySaltLengthBytes; 222 } 223 224 225 226 /** 227 * Specifies the length in bytes to use for the key factory salt when 228 * generating the encryption key from the provided password. 229 * 230 * @param keyFactorySaltLengthBytes The length in bytes to use for the key 231 * factory salt when generating the 232 * encryption key from the provided 233 * password. It must be greater than zero. 234 */ 235 public void setKeyFactorySaltLengthBytes(final int keyFactorySaltLengthBytes) 236 { 237 Validator.ensureTrue((keyFactorySaltLengthBytes > 0), 238 "The key factory salt length must be greater than zero bytes."); 239 this.keyFactorySaltLengthBytes = keyFactorySaltLengthBytes; 240 } 241 242 243 244 /** 245 * Retrieves the algorithm identifier for the cipher transformation to use 246 * when encrypting a PKCS #8 private key. 247 * 248 * @return The algorithm identifier for the cipher transformation to use when 249 * encrypting a PKCS #8 private key. 250 */ 251 @NotNull() 252 public PKCS5AlgorithmIdentifier getCipherTransformationAlgorithm() 253 { 254 return cipherTransformationAlgorithm; 255 } 256 257 258 259 /** 260 * Specifies the algorithm identifier for the cipher transformation to use 261 * when encrypting a PKCS #8 private key. 262 * 263 * @param cipherTransformationAlgorithm The algorithm identifier for the 264 * cipher transformation to use when 265 * encrypting a PKCS #8 private key. 266 * It must not be {@code null}, and it 267 * must represent a valid cipher 268 * transformation. 269 * 270 * @throws CertException If the provided algorithm identifier does not 271 * represent a valid cipher transformation. 272 */ 273 public void setCipherTransformationAlgorithm( 274 @NotNull final PKCS5AlgorithmIdentifier cipherTransformationAlgorithm) 275 throws CertException 276 { 277 if (! PKCS5AlgorithmIdentifier.getCipherTransformations().contains( 278 cipherTransformationAlgorithm)) 279 { 280 throw new CertException( 281 ERR_PKCS8_ENC_PROPS_INVALID_CIPHER_TRANSFORMATION_ALG.get( 282 cipherTransformationAlgorithm.getName(), 283 cipherTransformationAlgorithm.getDescription())); 284 } 285 286 this.cipherTransformationAlgorithm = cipherTransformationAlgorithm; 287 } 288 289 290 291 /** 292 * Retrieves a string representation of the PKCS #8 encryption properties. 293 * 294 * @return A string representation of the PKCS #8 encryption properties. 295 */ 296 @NotNull() 297 public String toString() 298 { 299 final StringBuilder buffer = new StringBuilder(); 300 toString(buffer); 301 return buffer.toString(); 302 } 303 304 305 306 /** 307 * Appends a string representation of the PKCS #8 encryption properties to the 308 * provided buffer. 309 * 310 * @param buffer The buffer to which the information should be appended. It 311 * must not be {@code null}. 312 */ 313 public void toString(@NotNull final StringBuilder buffer) 314 { 315 buffer.append("PKCS8EncryptionProperties(keyFactoryPRFAlgorithm='"); 316 buffer.append(keyFactoryPRFAlgorithm.getName()); 317 buffer.append("', keyFactoryIterationCount="); 318 buffer.append(keyFactoryIterationCount); 319 buffer.append(", keyFactorySaltLengthBytes="); 320 buffer.append(keyFactorySaltLengthBytes); 321 buffer.append(", cipherTransformation='"); 322 buffer.append(cipherTransformationAlgorithm.getName()); 323 buffer.append("')"); 324 } 325}