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}