001/*
002 * Copyright 2017-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2017-2019 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.listener;
022
023
024
025import com.unboundid.ldap.sdk.LDAPException;
026import com.unboundid.ldap.sdk.ResultCode;
027import com.unboundid.util.Debug;
028import com.unboundid.util.StaticUtils;
029import com.unboundid.util.ThreadSafety;
030import com.unboundid.util.ThreadSafetyLevel;
031
032import static com.unboundid.ldap.listener.ListenerMessages.*;
033
034
035
036/**
037 * This class provides an implementation of a password encoder output formatter
038 * that will use hexadecimal digits to represent the bytes of the encoded
039 * password.
040 */
041@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
042public final class HexPasswordEncoderOutputFormatter
043       extends PasswordEncoderOutputFormatter
044{
045  /**
046   * The singleton instance of this hex password encoder output formatter that
047   * uses lowercase versions of the hexadecimal digits 'a' through 'f'.
048   */
049  private static final HexPasswordEncoderOutputFormatter LOWERCASE_INSTANCE =
050       new HexPasswordEncoderOutputFormatter(true);
051
052
053
054  /**
055   * The singleton instance of this hex password encoder output formatter that
056   * uses uppercase versions of the hexadecimal digits 'A' through 'F'.
057   */
058  private static final HexPasswordEncoderOutputFormatter UPPERCASE_INSTANCE =
059       new HexPasswordEncoderOutputFormatter(false);
060
061
062
063  // Indicates whether to use lowercase letters for hexadecimal digits 'A'
064  // through 'F'.
065  private final boolean useLowercaseLetters;
066
067
068
069  /**
070   * Creates an instance of this hex password encoder output formatter with the
071   * specified configuration.
072   *
073   * @param  useLowercaseLetters Indicates whether the hexadecimal digits 'A'
074   *                             through 'F' should be output as lowercase
075   *                             letters (if {@code true} or as uppercase
076   *                             letters (if {@code false}).
077   */
078  private HexPasswordEncoderOutputFormatter(final boolean useLowercaseLetters)
079  {
080    this.useLowercaseLetters = useLowercaseLetters;
081  }
082
083
084
085  /**
086   * Retrieves a singleton instance of this hex password encoder that will
087   * represent the hexadecimal digits 'A' through 'F' as lowercase letters.
088   *
089   * @return  The hex password encoder instance.
090   */
091  public static HexPasswordEncoderOutputFormatter getLowercaseInstance()
092  {
093    return LOWERCASE_INSTANCE;
094  }
095
096
097
098  /**
099   * Retrieves a singleton instance of this hex password encoder that will
100   * represent the hexadecimal digits 'A' through 'F' as uppercase letters.
101   *
102   * @return  The hex password encoder instance.
103   */
104  public static HexPasswordEncoderOutputFormatter getUppercaseInstance()
105  {
106    return UPPERCASE_INSTANCE;
107  }
108
109
110
111  /**
112   * Indicates whether to represent the hexadecimal digits 'A' through 'F' as
113   * lowercase letters or uppercase letters.  Note that this setting only
114   * applies when formatting an encoded password.  When un-formatting a
115   * password, either uppercase or lowercase letters will be properly handled.
116   *
117   * @return  {@code true} if hexadecimal digits 'A' through 'F' should be
118   *          represented as lowercase letters, or {@code false} if they should
119   *          be represented as uppercase letters.
120   */
121  public boolean useLowercaseLetters()
122  {
123    return useLowercaseLetters;
124  }
125
126
127
128  /**
129   * {@inheritDoc}
130   */
131  @Override()
132  public byte[] format(final byte[] unformattedData)
133         throws LDAPException
134  {
135    String hexString = StaticUtils.toHex(unformattedData);
136    if (! useLowercaseLetters)
137    {
138      hexString = hexString.toUpperCase();
139    }
140
141    return StaticUtils.getBytes(hexString);
142  }
143
144
145
146  /**
147   * {@inheritDoc}
148   */
149  @Override()
150  public byte[] unFormat(final byte[] formattedData)
151         throws LDAPException
152  {
153    try
154    {
155      return StaticUtils.fromHex(StaticUtils.toUTF8String(formattedData));
156    }
157    catch (final Exception e)
158    {
159      Debug.debugException(e);
160      throw new LDAPException(ResultCode.PARAM_ERROR,
161           ERR_HEX_PW_FORMATTER_CANNOT_DECODE.get(), e);
162    }
163  }
164
165
166
167  /**
168   * {@inheritDoc}
169   */
170  @Override()
171  public void toString(final StringBuilder buffer)
172  {
173    buffer.append("HexPasswordEncoderOutputFormatter(useLowercaseLetters=");
174    buffer.append(useLowercaseLetters);
175    buffer.append(')');
176  }
177}