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.ldap.sdk.unboundidds;
037
038
039
040import java.io.Serializable;
041import java.security.GeneralSecurityException;
042import java.security.SecureRandom;
043import java.text.ParseException;
044import java.util.Arrays;
045
046import javax.crypto.BadPaddingException;
047import javax.crypto.Cipher;
048import javax.crypto.spec.GCMParameterSpec;
049
050import com.unboundid.util.Base64;
051import com.unboundid.util.ByteStringBuffer;
052import com.unboundid.util.CryptoHelper;
053import com.unboundid.util.Debug;
054import com.unboundid.util.NotMutable;
055import com.unboundid.util.NotNull;
056import com.unboundid.util.StaticUtils;
057import com.unboundid.util.ThreadLocalSecureRandom;
058import com.unboundid.util.ThreadSafety;
059import com.unboundid.util.ThreadSafetyLevel;
060import com.unboundid.util.Validator;
061
062import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*;
063
064
065
066/**
067 * This class provides a mechanism that can be used to encrypt and decrypt
068 * passwords using the same mechanism that the Ping Identity Directory Server
069 * uses for the AES256 password storage scheme (for clients that know the
070 * passphrase used to generate the encryption key).
071 * <BR>
072 * <BLOCKQUOTE>
073 *   <B>NOTE:</B>  This class, and other classes within the
074 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
075 *   supported for use against Ping Identity, UnboundID, and
076 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
077 *   for proprietary functionality or for external specifications that are not
078 *   considered stable or mature enough to be guaranteed to work in an
079 *   interoperable way with other types of LDAP servers.
080 * </BLOCKQUOTE>
081 * <BR>
082 * Note that this class requires strong encryption support in the underlying
083 * JVM.  For Java 7 JVMs, and for Java 8 JVMs prior to update 161, this requires
084 * installing unlimited strength jurisdiction policy files in the JVM.  For Java
085 * 8 JVMs starting with update 161, and for all later Java versions, strong
086 * encryption should be available by default.
087 * <BR><BR>
088 * The raw representation for encoded passwords is constructed as follows:
089 * <OL>
090 *   <LI>
091 *     A single byte that combines the encoding version and the padding length.
092 *     The least significant four bits represent a two's complement integer that
093 *     indicate the number of zero bytes that will be appended to the provided
094 *     password to make it a multiple of sixteen bytes.  The most significant
095 *     four bits represent the encoding version.  At present, we only support a
096 *     single encoding version in which all of those bits must be set to zero.
097 *     With this encoding version, the following properties will be used:
098 *     <UL>
099 *       <LI>Cipher Transformation:  AES/GCM/NoPadding</LI>
100 *       <LI>Key Factory Algorithm:  PBKDF2WithHmacSHA512</LI>
101 *       <LI>Key Factory Iteration Count:  32,768</LI>
102 *       <LI>Key Factory Salt Length:  128 bits (16 bytes)</LI>
103 *       <LI>Key Factory Generated Key length:  256 bits (32 bytes)</LI>
104 *       <LI>Initialization Vector Length:  128 bits (16 bytes)</LI>
105 *       <LI>GCM Tag Length:  128 bits</LI>
106 *       <LI>Padding Modulus:  16</LI>
107 *     </UL>
108 *   </LI>
109 *   <LI>
110 *     Sixteen bytes of random data generated by a secure random number
111 *     generator.  This represents the salt provided to the key factory for the
112 *     purpose of generating the secret key.
113 *   </LI>
114 *   <LI>
115 *     Sixteen bytes of random data generated by a secure random number
116 *     generator.  This represents the initialization vector that will be used
117 *     to randomize the cipher output.
118 *   </LI>
119 *   <LI>
120 *     One byte that represents a two's complement integer that indicates the
121 *     number of bytes in the ID of the encryption settings definition whose
122 *     passphrase is used to generate the encryption key.  The value must be
123 *     less than or equal to 255.  For current versions of the Ping Identity
124 *     Directory Server, it will typically be 32 bytes.
125 *   </LI>
126 *   <LI>
127 *     The bytes that comprise the raw ID of the encryption settings definition
128 *     whose passphrase will be used to generate the encryption key.
129 *   </LI>
130 *   <LI>
131 *     The bytes that comprise the encrypted password using the above settings.
132 *   </LI>
133 * </OL>
134 * <BR>
135 * The string representation of the encoded password is generated by appending
136 * the base64-encoded representation of the raw encoded bytes to the prefix
137 * "{AES256}".
138 * <BR><BR>
139 * When encrypting a password using this algorithm, the first step is to
140 * generate the encryption key.  This is done using a key factory, which
141 * combines a passphrase (obtained from an encryption settings definition), an
142 * iteration count, and a salt.
143 * <BR><BR>
144 * The second step is to apply any necessary padding to the password.  Because
145 * AES used in Galois Counter mode (GCM) behaves as a stream cipher, the size of
146 * the encrypted data can be used to determine the size of the plaintext that
147 * was encrypted.  This is undesirable when encrypting passwords because it can
148 * let an attacker know how long the user's password is.  Padding the password
149 * (by appending enough zero bytes to make its length a multiple of sixteen
150 * bytes) makes it impossible for an attacker to determine the size of the
151 * clear-text password.
152 * <BR><BR>
153 * The final step is to perform the encryption.  A cipher is created using the
154 * generated secret key and initialization vector, and it is used to encrypt the
155 * padded password.
156 * <BR><BR>
157 * Because this encoding uses reversible encryption rather than a one-way
158 * algorithm, there are two possible ways to verify that a provided plain-text
159 * password matches an encoded representation.  Both involve decoding the
160 * encoded representation of the password to extract the padding length, salt,
161 * initialization vector, and encryption settings definition ID.  Then, you can
162 * either encrypt the provided plaintext password with the same settings to
163 * verify that it yields the same encoded representation, or you can decrypt
164 * the encoded password and remove any padding to verify that it yields the same
165 * plaintext representation.
166 */
167@NotMutable()
168@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
169public final class AES256EncodedPassword
170       implements Serializable
171{
172  /**
173   * The bitmask that will be used to indicate an encoding version of zero.
174   * Only the most significant four bits of this byte will be used.  The least
175   * significant four bits of the first byte will be used to indicate the number
176   * of padding bytes that must be appended to the clear-text password to make
177   * its length a multiple of sixteen bytes.
178   */
179  public static final byte ENCODING_VERSION_0_MASK = (byte) 0x00;
180
181
182
183  /**
184   * The integer value for encoding version 0.
185   */
186  public static final int ENCODING_VERSION_0 = 0;
187
188
189
190  /**
191   * The GCM tag length in bits to use with an encoding version of zero.
192   */
193  public static final int ENCODING_VERSION_0_GCM_TAG_LENGTH_BITS = 128;
194
195
196
197  /**
198   * The generated secret key length in bits to use with an encoding version of
199   * zero.
200   */
201  public static final int ENCODING_VERSION_0_GENERATED_KEY_LENGTH_BITS = 256;
202
203
204
205  /**
206   * The size in bytes to use for the initialization vector with an encoding
207   * version of zero.
208   */
209  public static final int ENCODING_VERSION_0_IV_LENGTH_BYTES = 16;
210
211
212
213  /**
214   * The key factory iteration count to use with an encoding version of zero.
215   */
216  public static final int ENCODING_VERSION_0_KEY_FACTORY_ITERATION_COUNT =
217       32_768;
218
219
220
221  /**
222   * The size in bytes to use for the key factory salt with an encoding version
223   * of zero.
224   */
225  public static final int ENCODING_VERSION_0_KEY_FACTORY_SALT_LENGTH_BYTES = 16;
226
227
228
229  /**
230   * The padding modulus to use with an encoding version of zero.
231   */
232  public static final int ENCODING_VERSION_0_PADDING_MODULUS = 16;
233
234
235
236  /**
237   * The name of the cipher algorithm that should be used with an encoding
238   * version of zero.
239   */
240  @NotNull public static final String ENCODING_VERSION_0_CIPHER_ALGORITHM =
241       "AES";
242
243
244
245  /**
246   * The name of the cipher transformation that should be used with an encoding
247   * version of zero.
248   */
249  @NotNull public static final String ENCODING_VERSION_0_CIPHER_TRANSFORMATION =
250       "AES/GCM/NoPadding";
251
252
253
254  /**
255   * The name of the key factory algorithm should be used with an encoding
256   * version of zero.
257   */
258  @NotNull public static final String ENCODING_VERSION_0_KEY_FACTORY_ALGORITHM =
259       "PBKDF2WithHmacSHA512";
260
261
262
263  /**
264   * The prefix that will appear at the beginning of the string representation
265   * for an encoded password.
266   */
267  @NotNull public static final String PASSWORD_STORAGE_SCHEME_PREFIX =
268       "{AES256}";
269
270
271
272  /**
273   * The serial version UID for this serializable class.
274   */
275  private static final long serialVersionUID = 8663129897722695672L;
276
277
278
279  // The bytes that comprise the complete raw encoded representation of the
280  // password.
281  @NotNull private final byte[] encodedRepresentation;
282
283  // The bytes that comprise the encrypted representation of the padded
284  // password.
285  @NotNull private final byte[] encryptedPaddedPassword;
286
287  // The bytes that comprise the raw encryption settings definition ID whose
288  // passphrase was used to generate the encoded password.
289  @NotNull private final byte[] encryptionSettingsDefinitionID;
290
291  // The initialization vector used to randomize the output of the encrypted
292  // password.
293  @NotNull private final byte[] initializationVector;
294
295  // The salt used in the course of generating the encryption key from the
296  // encryption settings definition passphrase.
297  @NotNull private final byte[] keyFactorySalt;
298
299  // The encoding version used for the password.
300  private final int encodingVersion;
301
302  // The number of zero bytes that were appended to the clear-text password
303  // before it was encrypted.
304  private final int paddingBytes;
305
306
307
308  /**
309   * Creates a new encoded password with the provided information.
310   *
311   * @param  encodedRepresentation
312   *              The bytes that comprise the complete raw encoded
313   *              representation of the password.
314   * @param  encodingVersion
315   *              The encoding version for this encoded password.
316   * @param  paddingBytes
317   *              The number of bytes of padding that need to be appended to the
318   *              clear-text password to make its length a multiple of sixteen
319   *              bytes.
320   * @param  keyFactorySalt
321   *              The salt used to generate the encryption key from the
322   *              encryption settings definition passphrase.
323   * @param  initializationVector
324   *              The initialization vector used to randomize the cipher output.
325   * @param  encryptionSettingsDefinitionID
326   *              The bytes that comprise the raw encryption settings definition
327   *              ID whose passphrase was used to generate the encoded password.
328   * @param  encryptedPaddedPassword
329   *              The bytes that comprise the encrypted representation of the
330   *              padded password.
331   */
332  private AES256EncodedPassword(
333               @NotNull final byte[] encodedRepresentation,
334               final int encodingVersion,
335               final int paddingBytes,
336               @NotNull final byte[] keyFactorySalt,
337               @NotNull final byte[] initializationVector,
338               @NotNull final byte[] encryptionSettingsDefinitionID,
339               @NotNull final byte[] encryptedPaddedPassword)
340  {
341    this.encodedRepresentation = encodedRepresentation;
342    this.encodingVersion = encodingVersion;
343    this.paddingBytes = paddingBytes;
344    this.keyFactorySalt = keyFactorySalt;
345    this.initializationVector = initializationVector;
346    this.encryptionSettingsDefinitionID = encryptionSettingsDefinitionID;
347    this.encryptedPaddedPassword = encryptedPaddedPassword;
348  }
349
350
351
352  /**
353   * Retrieves the encoding version for this encoded password.
354   *
355   * @return  The encoding version for this encoded password.
356   */
357  public int getEncodingVersion()
358  {
359    return encodingVersion;
360  }
361
362
363
364  /**
365   * Retrieves the number of bytes of padding that need to be appended to the
366   * clear-text password to make its length a multiple of sixteen bytes.
367   *
368   * @return  The number of bytes of padding that need to be appended to the
369   *          clear-text password to make its length a multiple of sixteen
370   *          bytes.
371   */
372  public int getPaddingBytes()
373  {
374    return paddingBytes;
375  }
376
377
378
379  /**
380   * Retrieves the salt used to generate the encryption key from the encryption
381   * settings definition passphrase.
382   *
383   * @return  The salt used to generate the encryption key from the encryption
384   *          settings definition passphrase.
385   */
386  @NotNull()
387  public byte[] getKeyFactorySalt()
388  {
389    return keyFactorySalt;
390  }
391
392
393
394  /**
395   * Retrieves the initialization vector used to randomize the cipher output.
396   *
397   * @return  The initialization vector used to randomize the cipher output.
398   */
399  @NotNull()
400  public byte[] getInitializationVector()
401  {
402    return initializationVector;
403  }
404
405
406
407  /**
408   * Retrieves the bytes that comprise the raw ID of the encryption settings
409   * definition whose passphrase is used to generate the encryption key.
410   *
411   * @return  A bytes that comprise the raw ID of the encryption settings
412   *          definition whose passphrase is used to generate the encryption
413   *          key.
414   */
415  @NotNull()
416  public byte[] getEncryptionSettingsDefinitionIDBytes()
417  {
418    return encryptionSettingsDefinitionID;
419  }
420
421
422
423  /**
424   * Retrieves a string representation of the ID of the encryption settings
425   * definition whose passphrase is used to generate the encryption key.
426   *
427   * @return  A string representation of the ID of the encryption settings
428   *          definition whose passphrase is used to generate the encryption
429   *          key.
430   */
431  @NotNull()
432  public String getEncryptionSettingsDefinitionIDString()
433  {
434    return StaticUtils.toUpperCase(
435         StaticUtils.toHex(encryptionSettingsDefinitionID));
436  }
437
438
439
440  /**
441   * Retrieves the bytes that comprise the complete raw encoded representation
442   * of the password.
443   *
444   * @return  The bytes that comprise the complete raw encoded representation of
445   *          the password.
446   */
447  @NotNull()
448  public byte[] getEncodedRepresentation()
449  {
450    return encodedRepresentation;
451  }
452
453
454
455  /**
456   * Retrieves the string representation of this AES256 password.
457   *
458   * @param  includeScheme  Indicates whether to include the "{AES256}" prefix
459   *                        at the beginning of the string representation.
460   *
461   * @return  The string representation of this encoded password.
462   */
463  @NotNull()
464  public String getStringRepresentation(final boolean includeScheme)
465  {
466    final String base64String = Base64.encode(encodedRepresentation);
467    if (includeScheme)
468    {
469      return PASSWORD_STORAGE_SCHEME_PREFIX + base64String;
470    }
471    else
472    {
473      return base64String;
474    }
475  }
476
477
478
479  /**
480   * Encodes a password using the provided information.
481   *
482   * @param  encryptionSettingsDefinitionID
483   *              A string with the hexadecimal representation of the
484   *              encryption settings definition whose passphrase was used to
485   *              generate the encoded password.  It must not be
486   *              {@code null} or empty, and it must represent a valid
487   *              hexadecimal string whose length is an even number less than
488   *              or equal to 510 bytes.
489   * @param  encryptionSettingsDefinitionPassphrase
490   *              The passphrase associated with the specified encryption
491   *              settings definition.  It must not be {@code null} or empty.
492   * @param  clearTextPassword
493   *              The clear-text password to encode.  It must not be
494   *              {@code null} or empty.
495   *
496   * @return  An object with all of the encoded password details.
497   *
498   * @throws  GeneralSecurityException  If a problem occurs while attempting to
499   *                                    perform any of the cryptographic
500   *                                    processing.
501   *
502   * @throws  ParseException  If the provided encryption settings definition ID
503   *                          cannot be parsed as a valid hexadecimal string.
504   */
505  @NotNull()
506  public static AES256EncodedPassword encode(
507              @NotNull final String encryptionSettingsDefinitionID,
508              @NotNull final String encryptionSettingsDefinitionPassphrase,
509              @NotNull final String clearTextPassword)
510         throws GeneralSecurityException, ParseException
511  {
512    final byte[] encryptionSettingsDefinitionIDBytes =
513         StaticUtils.fromHex(encryptionSettingsDefinitionID);
514
515    final char[] encryptionSettingsDefinitionPassphraseChars =
516         encryptionSettingsDefinitionPassphrase.toCharArray();
517    final byte[] clearTextPasswordBytes =
518         StaticUtils.getBytes(clearTextPassword);
519
520    try
521    {
522      return encode(encryptionSettingsDefinitionIDBytes,
523           encryptionSettingsDefinitionPassphraseChars, clearTextPasswordBytes);
524    }
525    finally
526    {
527      Arrays.fill(encryptionSettingsDefinitionPassphraseChars, '\u0000');
528      Arrays.fill(clearTextPasswordBytes, (byte) 0x00);
529    }
530  }
531
532
533
534  /**
535   * Encodes a password using the provided information.
536   *
537   * @param  encryptionSettingsDefinitionID
538   *              The bytes that comprise the raw encryption settings definition
539   *              ID whose passphrase was used to generate the encoded password.
540   *              It must not be {@code null} or empty, and its length must be
541   *              less than or equal to 255 bytes.
542   * @param  encryptionSettingsDefinitionPassphrase
543   *              The passphrase associated with the specified encryption
544   *              settings definition.  It must not be {@code null} or empty.
545   * @param  clearTextPassword
546   *              The bytes that comprise the clear-text password to encode.
547   *              It must not be {@code null} or empty.
548   *
549   * @return  An object with all of the encoded password details.
550   *
551   * @throws  GeneralSecurityException  If a problem occurs while attempting to
552   *                                    perform any of the cryptographic
553   *                                    processing.
554   */
555  @NotNull()
556  public static AES256EncodedPassword encode(
557              @NotNull final byte[] encryptionSettingsDefinitionID,
558              @NotNull final char[] encryptionSettingsDefinitionPassphrase,
559              @NotNull final byte[] clearTextPassword)
560         throws GeneralSecurityException
561  {
562    final SecureRandom random = ThreadLocalSecureRandom.get();
563
564    final byte[] keyFactorySalt =
565         new byte[ENCODING_VERSION_0_KEY_FACTORY_SALT_LENGTH_BYTES];
566    random.nextBytes(keyFactorySalt);
567
568    final byte[] initializationVector =
569         new byte[ENCODING_VERSION_0_IV_LENGTH_BYTES];
570    random.nextBytes(initializationVector);
571
572    return encode(encryptionSettingsDefinitionID,
573         encryptionSettingsDefinitionPassphrase, keyFactorySalt,
574         initializationVector, clearTextPassword);
575  }
576
577
578
579  /**
580   * Encodes a password using the provided information.
581   *
582   * @param  encryptionSettingsDefinitionID
583   *              The bytes that comprise the raw encryption settings definition
584   *              ID whose passphrase was used to generate the encoded password.
585   *              It must not be {@code null} or empty, and its length must be
586   *              less than or equal to 255 bytes.
587   * @param  encryptionSettingsDefinitionPassphrase
588   *              The passphrase associated with the specified encryption
589   *              settings definition.  It must not be {@code null} or empty.
590   * @param  keyFactorySalt
591   *              The salt used to generate the encryption key from the
592   *              encryption settings definition passphrase.  It must not be
593   *              {@code null} and it must have a length of exactly 16 bytes.
594   * @param  initializationVector
595   *              The initialization vector used to randomize the cipher output.
596   *              It must not be [@code null} and it must have a length of
597   *              exactly 16 bytes.
598   * @param  clearTextPassword
599   *              The bytes that comprise the clear-text password to encode.
600   *              It must not be {@code null} or empty.
601   *
602   * @return  An object with all of the encoded password details.
603   *
604   * @throws  GeneralSecurityException  If a problem occurs while attempting to
605   *                                    perform any of the cryptographic
606   *                                    processing.
607   */
608  @NotNull()
609  public static AES256EncodedPassword encode(
610              @NotNull final byte[] encryptionSettingsDefinitionID,
611              @NotNull final char[] encryptionSettingsDefinitionPassphrase,
612              @NotNull final byte[] keyFactorySalt,
613              @NotNull final byte[] initializationVector,
614              @NotNull final byte[] clearTextPassword)
615         throws GeneralSecurityException
616  {
617    final AES256EncodedPasswordSecretKey secretKey =
618         AES256EncodedPasswordSecretKey.generate(encryptionSettingsDefinitionID,
619              encryptionSettingsDefinitionPassphrase, keyFactorySalt);
620    try
621    {
622      return encode(secretKey, initializationVector, clearTextPassword);
623    }
624    finally
625    {
626      secretKey.destroy();
627    }
628  }
629
630
631
632  /**
633   * Encodes a password using the provided information.
634   *
635   * @param  secretKey
636   *              The secret key that should be used to encrypt the password.
637   *              It must not be {@code null}.  The secret key can be reused
638   *              when
639   * @param  initializationVector
640   *              The initialization vector used to randomize the cipher output.
641   *              It must not be [@code null} and it must have a length of
642   *              exactly 16 bytes.
643   * @param  clearTextPassword
644   *              The bytes that comprise the clear-text password to encode.
645   *              It must not be {@code null} or empty.
646   *
647   * @return  An object with all of the encoded password details.
648   *
649   * @throws  GeneralSecurityException  If a problem occurs while attempting to
650   *                                    perform any of the cryptographic
651   *                                    processing.
652   */
653  @NotNull()
654  public static AES256EncodedPassword encode(
655              @NotNull final AES256EncodedPasswordSecretKey secretKey,
656              @NotNull final byte[] initializationVector,
657              @NotNull final byte[] clearTextPassword)
658         throws GeneralSecurityException
659  {
660    // Validate all of the provided parameters.
661    Validator.ensureNotNull(secretKey,
662         "AES256EncodedPassword.encode.secretKey must not be null.");
663
664    Validator.ensureNotNull(initializationVector,
665         "AES256EncodedPassword.encode.initializationVector must not be null.");
666    if (initializationVector.length != ENCODING_VERSION_0_IV_LENGTH_BYTES)
667    {
668      Validator.violation("AES256EncodedPassword.encode.initializationVector " +
669           "must have a length of exactly " +
670           ENCODING_VERSION_0_IV_LENGTH_BYTES + " bytes.  The provided " +
671           "initialization vector had a length of " +
672           initializationVector.length + " bytes.");
673    }
674
675    Validator.ensureNotNullOrEmpty(clearTextPassword,
676         "AES256EncodedPassword.encode.clearTextPassword must not be null or " +
677              "empty.");
678
679
680    // Generate a padded representation of the password.
681    final byte[] paddedClearTextPassword;
682    final int paddingBytesNeeded;
683    final int clearTextPasswordLengthModulus =
684         clearTextPassword.length % ENCODING_VERSION_0_PADDING_MODULUS;
685    if (clearTextPasswordLengthModulus == 0)
686    {
687      paddedClearTextPassword = clearTextPassword;
688      paddingBytesNeeded = 0;
689    }
690    else
691    {
692      paddingBytesNeeded =
693           ENCODING_VERSION_0_PADDING_MODULUS - clearTextPasswordLengthModulus;
694      paddedClearTextPassword =
695           new byte[clearTextPassword.length + paddingBytesNeeded];
696      Arrays.fill(paddedClearTextPassword, (byte) 0x00);
697      System.arraycopy(clearTextPassword, 0, paddedClearTextPassword, 0,
698           clearTextPassword.length);
699    }
700
701
702    // Create and initialize the cipher and use it to encrypt the padded
703    // password.
704    final Cipher cipher =
705         CryptoHelper.getCipher(ENCODING_VERSION_0_CIPHER_TRANSFORMATION);
706    cipher.init(Cipher.ENCRYPT_MODE, secretKey.getSecretKey(),
707         new GCMParameterSpec(ENCODING_VERSION_0_GCM_TAG_LENGTH_BITS,
708              initializationVector));
709    final byte[] encryptedPaddedPassword =
710         cipher.doFinal(paddedClearTextPassword);
711
712
713    // Generate the raw encoded representation of the password.
714    final ByteStringBuffer buffer = new ByteStringBuffer();
715
716    // The first byte will combine the encoding version (the upper four bits)
717    // and the number of padding bytes (the lower four bits).
718    buffer.append((byte)
719         ((ENCODING_VERSION_0_MASK & 0xF0) | (paddingBytesNeeded & 0x0F)));
720
721    // The next 16 bytes will be the salt.
722    final byte[] keyFactorySalt = secretKey.getKeyFactorySalt();
723    buffer.append(keyFactorySalt);
724
725    // The next 16 bytes will be the initialization vector.
726    buffer.append(initializationVector);
727
728    // The next byte will be the number of bytes in the raw encryption settings
729    // definition ID, followed by the encoded ID.
730    final byte[] encryptionSettingsDefinitionID =
731         secretKey.getEncryptionSettingsDefinitionID();
732    buffer.append((byte) (encryptionSettingsDefinitionID.length & 0xFF));
733    buffer.append(encryptionSettingsDefinitionID);
734
735    // The remainder of the encoded representation will be the encrypted
736    // padded password.
737    buffer.append(encryptedPaddedPassword);
738
739
740    // Create and return an object with all of the encoded password details.
741    return new AES256EncodedPassword(buffer.toByteArray(), ENCODING_VERSION_0,
742         paddingBytesNeeded, keyFactorySalt, initializationVector,
743         encryptionSettingsDefinitionID, encryptedPaddedPassword);
744  }
745
746
747
748  /**
749   * Decodes the provided password into its component parts.
750   *
751   * @param  encodedPassword
752   *              The string representation of the encoded password to be
753   *              decoded.  It must not be {@code null} or empty, and it must
754   *              contain the base64-encoded representation of the raw encoded
755   *              password, optionally preceded by the "{AES256}" prefix.
756   *
757   * @return  The decoded representation of the provided password.
758   *
759   * @throws  ParseException  If the provided string does not represent a valid
760   *                          encoded password.
761   */
762  @NotNull()
763  public static AES256EncodedPassword decode(
764              @NotNull final String encodedPassword)
765         throws ParseException
766  {
767    Validator.ensureNotNullOrEmpty(encodedPassword,
768         "AES256EncodedPassword.decode.encodedPassword must not be null or " +
769              "empty.");
770
771
772    // If the provided string starts with a prefix, then strip it off.
773    final int base64StartPos;
774    final String base64EncodedString;
775    if (encodedPassword.startsWith(PASSWORD_STORAGE_SCHEME_PREFIX))
776    {
777      base64StartPos = PASSWORD_STORAGE_SCHEME_PREFIX.length();
778      base64EncodedString = encodedPassword.substring(base64StartPos);
779    }
780    else
781    {
782      base64StartPos = 0;
783      base64EncodedString = encodedPassword;
784    }
785
786
787    // Base64-decode the data.
788    final byte[] encodedPasswordBytes;
789    try
790    {
791      encodedPasswordBytes = Base64.decode(base64EncodedString);
792    }
793    catch (final ParseException e)
794    {
795      Debug.debugException(e);
796      throw new ParseException(
797           ERR_AES256_ENC_PW_DECODE_NOT_BASE64.get(
798                StaticUtils.getExceptionMessage(e)),
799           base64StartPos);
800    }
801
802
803    return decode(encodedPasswordBytes);
804  }
805
806
807
808  /**
809   * Decodes the provided password into its component parts.
810   *
811   * @param  encodedPassword
812   *              The bytes that comprise the complete raw encoded
813   *              representation of the password.  It must not be {@code null}
814   *              or empty.
815   *
816   * @return  The decoded representation of the provided password.
817   *
818   * @throws  ParseException  If the provided string does not represent a valid
819   *                          encoded password.
820   */
821  @NotNull()
822  public static AES256EncodedPassword decode(
823              @NotNull final byte[] encodedPassword)
824         throws ParseException
825  {
826    Validator.ensureNotNullOrEmpty(encodedPassword,
827         "AES256EncodedPassword.decode.encodedPassword must not be null or " +
828              "empty.");
829
830
831    // Make sure that the length is at least 36 bytes long.  This isn't long
832    // enough for a valid encoded password, but it's long enough to let us get a
833    // good starting point.
834    if (encodedPassword.length < 36)
835    {
836      throw new ParseException(
837           ERR_AES256_ENC_PW_DECODE_TOO_SHORT_INITIAL.get(
838                encodedPassword.length),
839           0);
840    }
841
842
843    // The first byte must contain the encoding version and the number of bytes
844    // of padding.
845    final byte encodingVersionAndPaddingByte = encodedPassword[0];
846    final int encodingVersion = (encodingVersionAndPaddingByte >> 4) & 0x0F;
847    if (encodingVersion != ENCODING_VERSION_0)
848    {
849      throw new ParseException(
850           ERR_AES256_ENC_PW_DECODE_UNSUPPORTED_ENCODING_VERSION.get(
851                encodingVersion, ENCODING_VERSION_0),
852           0);
853    }
854
855    final int paddingBytes = (encodingVersionAndPaddingByte & 0x0F);
856
857
858    // The next 16 bytes must contain the salt.
859    final byte[] keyFactorySalt =
860         new byte[ENCODING_VERSION_0_KEY_FACTORY_SALT_LENGTH_BYTES];
861    System.arraycopy(encodedPassword, 1, keyFactorySalt, 0,
862         keyFactorySalt.length);
863
864
865    // The next 16 bytes must contain the initialization vector.
866    final byte[] initializationVector =
867         new byte[ENCODING_VERSION_0_IV_LENGTH_BYTES];
868    System.arraycopy(encodedPassword, 1 + keyFactorySalt.length,
869         initializationVector, 0, initializationVector.length);
870
871
872    // The next byte must indicate how many bytes are in the encryption settings
873    // definition ID.  That should then be followed by the specified number of
874    // bytes of the encryption settings definition ID.
875    final int esdIDLengthPos =
876         1 + keyFactorySalt.length + initializationVector.length;
877    final int esdIDLength = encodedPassword[esdIDLengthPos] & 0xFF;
878    if (encodedPassword.length < (esdIDLengthPos + 2 + esdIDLength))
879    {
880      throw new ParseException(
881           ERR_AES256_ENC_PW_DECODE_TOO_SHORT_FOR_ESD_ID.get(
882                encodedPassword.length, esdIDLength),
883           esdIDLengthPos);
884    }
885
886    final byte[] encryptionSettingsDefinitionID = new byte[esdIDLength];
887    System.arraycopy(encodedPassword, esdIDLengthPos + 1,
888         encryptionSettingsDefinitionID, 0, esdIDLength);
889
890
891    // The remainder of the encoded password must be the encrypted padded
892    // password.
893    final int encryptedPaddedPasswordPos =
894         esdIDLengthPos + 1 + esdIDLength;
895    final int encryptedPaddedPasswordLength = encodedPassword.length -
896         encryptedPaddedPasswordPos;
897    final byte[] encryptedPaddedPassword =
898         new byte[encryptedPaddedPasswordLength];
899    System.arraycopy(encodedPassword, encryptedPaddedPasswordPos,
900         encryptedPaddedPassword, 0, encryptedPaddedPasswordLength);
901
902    return new AES256EncodedPassword(encodedPassword, encodingVersion,
903         paddingBytes, keyFactorySalt, initializationVector,
904         encryptionSettingsDefinitionID, encryptedPaddedPassword);
905  }
906
907
908
909  /**
910   * Decrypts this encoded password to obtain the original clear-text password
911   * used to generate it.
912   *
913   * @param  encryptionSettingsDefinitionPassphrase
914   *              The passphrase associated with the encryption settings
915   *              definition used to encrypt the password.  It must not be
916   *              {@code null} or empty.
917   *
918   * @return  The original clear-txt password used to generate this encoded
919   *          representation.
920   *
921   * @throws  GeneralSecurityException  If an error occurs while attempting to
922   *                                    decrypt the password using the
923   *                                    provided encryption settings ID
924   *                                    passphrase.
925   */
926  @NotNull()
927  public byte[] decrypt(
928              @NotNull final String encryptionSettingsDefinitionPassphrase)
929         throws GeneralSecurityException
930  {
931    final char[] passphraseChars =
932         encryptionSettingsDefinitionPassphrase.toCharArray();
933
934    try
935    {
936      return decrypt(passphraseChars);
937    }
938    finally
939    {
940      Arrays.fill(passphraseChars, '\u0000');
941    }
942  }
943
944
945
946  /**
947   * Decrypts this encoded password to obtain the original clear-text password
948   * used to generate it.
949   *
950   * @param  encryptionSettingsDefinitionPassphrase
951   *              The passphrase associated with the encryption settings
952   *              definition used to encrypt the password.  It must not be
953   *              {@code null} or empty.
954   *
955   * @return  The original clear-txt password used to generate this encoded
956   *          representation.
957   *
958   * @throws  GeneralSecurityException  If an error occurs while attempting to
959   *                                    decrypt the password using the
960   *                                    provided encryption settings ID
961   *                                    passphrase.
962   */
963  @NotNull()
964  public byte[] decrypt(
965              @NotNull final char[] encryptionSettingsDefinitionPassphrase)
966         throws GeneralSecurityException
967  {
968    final AES256EncodedPasswordSecretKey secretKey =
969         AES256EncodedPasswordSecretKey.generate(encryptionSettingsDefinitionID,
970              encryptionSettingsDefinitionPassphrase, keyFactorySalt);
971
972    try
973    {
974      return decrypt(secretKey);
975    }
976    finally
977    {
978      secretKey.destroy();
979    }
980  }
981
982
983
984  /**
985   * Decrypts this encoded password to obtain the original clear-text password
986   * used to generate it.
987   *
988   * @param  secretKey
989   *              The that will be used to decrypt the password.  It must not
990   *              be {@code null}.
991   *
992   * @return  The original clear-txt password used to generate this encoded
993   *          representation.
994   *
995   * @throws  GeneralSecurityException  If an error occurs while attempting to
996   *                                    decrypt the password using the
997   *                                    provided encryption settings ID
998   *                                    passphrase.
999   */
1000  @NotNull()
1001  public byte[] decrypt(@NotNull final AES256EncodedPasswordSecretKey secretKey)
1002         throws GeneralSecurityException
1003  {
1004    Validator.ensureNotNull(secretKey,
1005         "AES256EncodedPassword.decrypt.secretKey must not be null.");
1006
1007
1008    // Create and initialize the cipher and use it to decrypt the padded
1009    // password.
1010    final Cipher cipher =
1011         CryptoHelper.getCipher(ENCODING_VERSION_0_CIPHER_TRANSFORMATION);
1012    cipher.init(Cipher.DECRYPT_MODE, secretKey.getSecretKey(),
1013         new GCMParameterSpec(ENCODING_VERSION_0_GCM_TAG_LENGTH_BITS,
1014              initializationVector));
1015    final byte[] decryptedPaddedPassword =
1016         cipher.doFinal(encryptedPaddedPassword);
1017
1018
1019    // Strip off any padding and return the resulting password.
1020    final byte[] decryptedPassword;
1021    if (paddingBytes > 0)
1022    {
1023      try
1024      {
1025        decryptedPassword =
1026             new byte[decryptedPaddedPassword.length - paddingBytes];
1027        for (int  i=0; i < decryptedPaddedPassword.length; i++)
1028        {
1029          if (i < decryptedPassword.length)
1030          {
1031            // This byte is not padding.
1032            decryptedPassword[i] = decryptedPaddedPassword[i];
1033          }
1034          else
1035          {
1036            // This byte is considered padding.  Make sure that it's 0x00.
1037            if (decryptedPaddedPassword[i] != 0x00)
1038            {
1039              throw new BadPaddingException(
1040                   ERR_AES256_ENC_PW_DECRYPT_NONZERO_PADDING.get(paddingBytes));
1041            }
1042          }
1043        }
1044
1045        System.arraycopy(decryptedPaddedPassword, 0, decryptedPassword, 0,
1046             decryptedPassword.length);
1047      }
1048      finally
1049      {
1050        Arrays.fill(decryptedPaddedPassword, (byte) 0x00);
1051      }
1052    }
1053    else
1054    {
1055      decryptedPassword = decryptedPaddedPassword;
1056    }
1057
1058    return decryptedPassword;
1059  }
1060
1061
1062
1063  /**
1064   * Retrieves a string representation of this AES256 password.
1065   *
1066   * @return  A string representation of this encoded password.
1067   */
1068  @Override()
1069  @NotNull()
1070  public String toString()
1071  {
1072    final StringBuilder buffer = new StringBuilder();
1073    toString(buffer);
1074    return buffer.toString();
1075  }
1076
1077
1078
1079  /**
1080   * Appends a string representation of this AES256 encoded password to the
1081   * provided buffer.
1082   *
1083   * @param  buffer  The buffer to which the information should be appended.
1084   */
1085  public void toString(@NotNull final StringBuilder buffer)
1086  {
1087    buffer.append("AES256EncodedPassword(stringRepresentation='");
1088    buffer.append(getStringRepresentation(true));
1089    buffer.append("', encodingVersion=");
1090    buffer.append(encodingVersion);
1091    buffer.append(", paddingBytes=");
1092    buffer.append(paddingBytes);
1093    buffer.append(", encryptionSettingsDefinitionIDHex='");
1094    StaticUtils.toHex(encryptionSettingsDefinitionID, buffer);
1095    buffer.append("', keyFactorySaltBytesHex='");
1096    StaticUtils.toHex(keyFactorySalt, buffer);
1097    buffer.append("', initializationVectorBytesHex='");
1098    StaticUtils.toHex(keyFactorySalt, buffer);
1099    buffer.append("')");
1100  }
1101}