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.BlowfishPasswordStorageSchemeCfg;
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 Blowfish reversible encryption algorithm. This
052 * implementation supports only the user password syntax and not the auth
053 * password syntax.
054 */
055 public class BlowfishPasswordStorageScheme
056 extends PasswordStorageScheme<BlowfishPasswordStorageSchemeCfg>
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 BlowfishPasswordStorageScheme()
077 {
078 super();
079 }
080
081
082
083 /**
084 * {@inheritDoc}
085 */
086 @Override()
087 public void initializePasswordStorageScheme(
088 BlowfishPasswordStorageSchemeCfg 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_BLOWFISH;
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 =
117 cryptoManager.encrypt(CIPHER_TRANSFORMATION_BLOWFISH,
118 KEY_SIZE_BLOWFISH, 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_BLOWFISH,
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_BLOWFISH);
147 buffer.append('}');
148
149 try
150 {
151 byte[] encodedBytes =
152 cryptoManager.encrypt(CIPHER_TRANSFORMATION_BLOWFISH,
153 KEY_SIZE_BLOWFISH, 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_BLOWFISH,
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_BLOWFISH,
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