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