001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.extensions;
028    
029    
030    
031    import java.util.Arrays;
032    
033    import org.opends.messages.Message;
034    import org.opends.server.admin.std.server.AESPasswordStorageSchemeCfg;
035    import org.opends.server.api.PasswordStorageScheme;
036    import org.opends.server.config.ConfigException;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.loggers.debug.DebugTracer;
039    import org.opends.server.types.*;
040    import org.opends.server.util.Base64;
041    
042    import static org.opends.messages.ExtensionMessages.*;
043    import static org.opends.server.extensions.ExtensionsConstants.*;
044    import static org.opends.server.loggers.debug.DebugLogger.*;
045    import static org.opends.server.util.StaticUtils.*;
046    
047    
048    
049    /**
050     * This class defines a Directory Server password storage scheme that will
051     * encode values using the AES reversible encryption algorithm.  This
052     * implementation supports only the user password syntax and not the auth
053     * password syntax.
054     */
055    public class AESPasswordStorageScheme
056           extends PasswordStorageScheme<AESPasswordStorageSchemeCfg>
057    {
058      /**
059       * The tracer object for the debug logger.
060       */
061      private static final DebugTracer TRACER = getTracer();
062    
063    
064    
065      // The reference to the Directory Server crypto manager that we will use to
066      // handle the encryption/decryption.
067      private CryptoManager cryptoManager;
068    
069    
070    
071      /**
072       * Creates a new instance of this password storage scheme.  Note that no
073       * initialization should be performed here, as all initialization should be
074       * done in the {@code initializePasswordStorageScheme} method.
075       */
076      public AESPasswordStorageScheme()
077      {
078        super();
079      }
080    
081    
082    
083      /**
084       * {@inheritDoc}
085       */
086      @Override()
087      public void initializePasswordStorageScheme(
088                       AESPasswordStorageSchemeCfg configuration)
089             throws ConfigException, InitializationException
090      {
091        cryptoManager = DirectoryServer.getCryptoManager();
092      }
093    
094    
095    
096      /**
097       * {@inheritDoc}
098       */
099      @Override()
100      public String getStorageSchemeName()
101      {
102        return STORAGE_SCHEME_NAME_AES;
103      }
104    
105    
106    
107      /**
108       * {@inheritDoc}
109       */
110      @Override()
111      public ByteString encodePassword(ByteString plaintext)
112             throws DirectoryException
113      {
114        try
115        {
116          byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_AES,
117                                                      KEY_SIZE_AES,
118                                                      plaintext.value());
119          return ByteStringFactory.create(Base64.encode(encodedBytes));
120        }
121        catch (Exception e)
122        {
123          if (debugEnabled())
124          {
125            TRACER.debugCaught(DebugLogLevel.ERROR, e);
126          }
127    
128          Message m = ERR_PWSCHEME_CANNOT_ENCRYPT.get(STORAGE_SCHEME_NAME_AES,
129                                                      getExceptionMessage(e));
130          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
131                                       m, e);
132        }
133      }
134    
135    
136    
137      /**
138       * {@inheritDoc}
139       */
140      @Override()
141      public ByteString encodePasswordWithScheme(ByteString plaintext)
142             throws DirectoryException
143      {
144        StringBuilder buffer = new StringBuilder();
145        buffer.append('{');
146        buffer.append(STORAGE_SCHEME_NAME_AES);
147        buffer.append('}');
148    
149        try
150        {
151          byte[] encodedBytes = cryptoManager.encrypt(CIPHER_TRANSFORMATION_AES,
152                                                      KEY_SIZE_AES,
153                                                      plaintext.value());
154          buffer.append(Base64.encode(encodedBytes));
155        }
156        catch (Exception e)
157        {
158          if (debugEnabled())
159          {
160            TRACER.debugCaught(DebugLogLevel.ERROR, e);
161          }
162    
163          Message m = ERR_PWSCHEME_CANNOT_ENCRYPT.get(STORAGE_SCHEME_NAME_AES,
164                                                      getExceptionMessage(e));
165          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
166                                       m, e);
167        }
168    
169        return ByteStringFactory.create(buffer.toString());
170      }
171    
172    
173    
174      /**
175       * {@inheritDoc}
176       */
177      @Override()
178      public boolean passwordMatches(ByteString plaintextPassword,
179                                     ByteString storedPassword)
180      {
181        try
182        {
183          byte[] decryptedPassword =
184               cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
185          return Arrays.equals(plaintextPassword.value(), decryptedPassword);
186        }
187        catch (Exception e)
188        {
189          if (debugEnabled())
190          {
191            TRACER.debugCaught(DebugLogLevel.ERROR, e);
192          }
193    
194          return false;
195        }
196      }
197    
198    
199    
200      /**
201       * {@inheritDoc}
202       */
203      @Override()
204      public boolean isReversible()
205      {
206        return true;
207      }
208    
209    
210    
211      /**
212       * {@inheritDoc}
213       */
214      @Override()
215      public ByteString getPlaintextValue(ByteString storedPassword)
216             throws DirectoryException
217      {
218        try
219        {
220          byte[] decryptedPassword =
221               cryptoManager.decrypt(Base64.decode(storedPassword.stringValue()));
222          return ByteStringFactory.create(decryptedPassword);
223        }
224        catch (Exception e)
225        {
226          if (debugEnabled())
227          {
228            TRACER.debugCaught(DebugLogLevel.ERROR, e);
229          }
230    
231          Message m = ERR_PWSCHEME_CANNOT_DECRYPT.get(STORAGE_SCHEME_NAME_AES,
232                                                      getExceptionMessage(e));
233          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
234                                       m, e);
235        }
236      }
237    
238    
239    
240      /**
241       * {@inheritDoc}
242       */
243      @Override()
244      public boolean supportsAuthPasswordSyntax()
245      {
246        // This storage scheme does not support the authentication password syntax.
247        return false;
248      }
249    
250    
251    
252      /**
253       * {@inheritDoc}
254       */
255      @Override()
256      public ByteString encodeAuthPassword(ByteString plaintext)
257             throws DirectoryException
258      {
259        Message message =
260            ERR_PWSCHEME_DOES_NOT_SUPPORT_AUTH_PASSWORD.get(getStorageSchemeName());
261        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
262      }
263    
264    
265    
266      /**
267       * {@inheritDoc}
268       */
269      @Override()
270      public boolean authPasswordMatches(ByteString plaintextPassword,
271                                         String authInfo, String authValue)
272      {
273        // This storage scheme does not support the authentication password syntax.
274        return false;
275      }
276    
277    
278    
279      /**
280       * {@inheritDoc}
281       */
282      @Override()
283      public ByteString getAuthPasswordPlaintextValue(String authInfo,
284                                                      String authValue)
285             throws DirectoryException
286      {
287        Message message =
288            ERR_PWSCHEME_DOES_NOT_SUPPORT_AUTH_PASSWORD.get(getStorageSchemeName());
289        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
290      }
291    
292    
293    
294      /**
295       * {@inheritDoc}
296       */
297      @Override()
298      public boolean isStorageSchemeSecure()
299      {
300        // This password storage scheme should be considered secure.
301        return true;
302      }
303    }
304