#
# old_revision [471dc0f5e3b2a6fc571aca4e14c0a5161cf7af0b]
#
# add_file "SoObjects/SOGo/NSData+Crypto.h"
#  content [4e1a09d2530e3934966cf7547ffc6ee9411b4d0d]
# 
# add_file "SoObjects/SOGo/NSData+Crypto.m"
#  content [6d71c327de926a32a542f1cbdf923c1d6435c3f2]
# 
# add_file "SoObjects/SOGo/NSString+Crypto.h"
#  content [a15042732241b52c399c8667dc0fd281f97bc131]
# 
# add_file "SoObjects/SOGo/NSString+Crypto.m"
#  content [24e1ff6773c04e588410609f312824912d333911]
# 
# patch "SoObjects/SOGo/GNUmakefile"
#  from [9e466added539ccacaecd830173afdf9d4755802]
#    to [0e4d9af53dddf014fe6fccf1d81e751d8dd2bc3c]
# 
# patch "SoObjects/SOGo/LDAPSource.m"
#  from [49cd1d275323dd81ba0ad5566e542b725856c4a9]
#    to [0570acb4f559ddabe647634f52a877d17dbbce2d]
# 
# patch "SoObjects/SOGo/NSString+Utilities.h"
#  from [d2661ef19253d96d64dcf11127ffe6882f90b4d4]
#    to [c38d80d6ebe9592a9f2ee954282718d7265dec51]
# 
# patch "SoObjects/SOGo/NSString+Utilities.m"
#  from [800b97cfc8f806e14c310ed8628c94a9934fd80a]
#    to [eb4c7cd585c64cb8fb0273c3e89be36da11e5f24]
# 
# patch "SoObjects/SOGo/SOGoUserManager.m"
#  from [9bf968b36558145edd71840dd180876c1d5d7175]
#    to [344659dcdf8d929bb824d8856d05c1de85ce801e]
# 
# patch "SoObjects/SOGo/SQLSource.m"
#  from [8e7fb09f6d34231ed0e1c57db516961d7a8bf0bb]
#    to [569afbdf32cf6a95315d8e99cd910a0abaa2e9ad]
#
============================================================
--- SoObjects/SOGo/GNUmakefile	9e466added539ccacaecd830173afdf9d4755802
+++ SoObjects/SOGo/GNUmakefile	0e4d9af53dddf014fe6fccf1d81e751d8dd2bc3c
@@ -46,6 +46,8 @@ SOGo_HEADER_FILES = \
 	NSObject+Utilities.h		\
 	NSString+DAV.h			\
 	NSString+Utilities.h		\
+	NSString+Crypto.h		\
+	NSData+Crypto.h			\
 	NSURL+DAV.h			\
 	\
 	SOGoAuthenticator.h		\
@@ -114,6 +116,8 @@ SOGo_OBJC_FILES = \
 	NSObject+Utilities.m		\
 	NSString+DAV.m  		\
 	NSString+Utilities.m		\
+	NSString+Crypto.m		\
+	NSData+Crypto.m			\
 	NSURL+DAV.m	  		\
 	\
 	SOGoSession.m			\
============================================================
--- SoObjects/SOGo/LDAPSource.m	49cd1d275323dd81ba0ad5566e542b725856c4a9
+++ SoObjects/SOGo/LDAPSource.m	0570acb4f559ddabe647634f52a877d17dbbce2d
@@ -40,6 +40,7 @@
 #import "LDAPSourceSchema.h"
 #import "NSArray+Utilities.h"
 #import "NSString+Utilities.h"
+#import "NSString+Crypto.h"
 #import "SOGoDomainDefaults.h"
 #import "SOGoSystemDefaults.h"
 
@@ -639,26 +640,13 @@ andMultipleBookingsField: (NSString *) n
  */
 - (NSString *) _encryptPassword: (NSString *) plainPassword
 {
-  if ([_userPasswordAlgorithm caseInsensitiveCompare: @"none"] == NSOrderedSame)
-    {
-      return plainPassword;
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
-    {
-      return [NSString stringWithFormat: @"{CRYPT}%@", [plainPassword asCryptStringUsingSalt: [plainPassword asMD5String]]];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"md5"] == NSOrderedSame)
-    {
-      return [NSString stringWithFormat: @"{MD5}%@", [plainPassword asMD5String]];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"sha"] == NSOrderedSame)
-    {
-      return [NSString stringWithFormat: @"{SHA}%@", [plainPassword asSHA1String]];
-    }
-  
-  [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
-  
-  return plainPassword;
+  NSString *pass;
+  pass = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
+
+  if (pass == nil)
+    [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
+
+  return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, pass];
 }
 
 //
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSData+Crypto.h	4e1a09d2530e3934966cf7547ffc6ee9411b4d0d
@@ -0,0 +1,57 @@
+/* NSData+Crypto.h - this file is part of SOGo
+ *
+ * Author: Nicolas Höft
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSDATA_CRYPTO_H
+#define NSDATA_CRYPTO_H
+
+#import <Foundation/NSData.h>
+
+@class NSObject;
+
+@interface NSData (SOGoCryptoExtension)
+
+- (NSData *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+                               withSalt: (NSData *) theSalt;
+
+- (NSData *) asMD5;
+- (NSData *) asSMD5UsingSalt: (NSData *) theSalt;
+- (NSData *) asSHA1;
+- (NSData *) asSSHAUsingSalt: (NSData *) theSalt;
+- (NSData *) asSHA256;
+- (NSData *) asSSHA256UsingSalt: (NSData *) theSalt;
+- (NSData *) asSHA512;
+- (NSData *) asSSHA512UsingSalt: (NSData *) theSalt;
+- (NSData *) asCramMD5;
+
+- (NSData *) asCryptUsingSalt: (NSData *) theSalt;
+- (NSData *) asMD5CryptUsingSalt: (NSData *) theSalt;
+
+- (NSData *) extractSalt: (NSString *) theScheme;
+
++ (NSData *) generateSaltForLength: (unsigned int) theLength
+                        withBase64: (BOOL) doBase64;
++ (NSData *) generateSaltForLength: (unsigned int) theLength;
+
++ (NSString *) encodeDataAsHexString: (NSData* ) theData;
++ (NSData *) decodeDataFromHexString: (NSString* ) theString;
+
+@end
+
+#endif /* NSDATA_CRYPTO_H */
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSData+Crypto.m	6d71c327de926a32a542f1cbdf923c1d6435c3f2
@@ -0,0 +1,617 @@
+/* NSData+Crypto.m - this file is part of SOGo
+ *
+ *
+ * Author: Nicolas Höft
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __OpenBSD__
+#include <crypt.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define _XOPEN_SOURCE 1
+#include <unistd.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+
+#import <Foundation/NSArray.h>
+#import <NGExtensions/NGBase64Coding.h>
+#import "NSData+Crypto.h"
+
+unsigned charTo4Bits(char c);
+
+
+@implementation NSData (SOGoCryptoExtension)
+
+/**
+ * Covert binary data to hex encoded data (lower-case).
+ *
+ * @param theData The NSData to be converted into a hex-encoded string.
+ * @return Hex-Encoded data
+ */
++ (NSString *) encodeDataAsHexString: (NSData *) theData
+{
+  unsigned int byteLength = [theData length], byteCounter = 0;
+  unsigned int stringLength = (byteLength * 2) + 1, stringCounter = 0;
+  unsigned char dstBuffer[stringLength];
+  unsigned char srcBuffer[byteLength];
+  unsigned char *srcPtr = srcBuffer;
+  [theData getBytes: srcBuffer];
+  const unsigned char t[16] = "0123456789abcdef";
+
+  for (; byteCounter < byteLength; byteCounter++)
+    {
+      unsigned src = *srcPtr;
+      dstBuffer[stringCounter++] = t[src >> 4];
+      dstBuffer[stringCounter++] = t[src & 15];
+      srcPtr++;
+    }
+
+  dstBuffer[stringCounter] = '\0';
+  return [NSString stringWithUTF8String: (char*)dstBuffer];
+}
+
+/**
+ * Covert hex-encoded data to binary data.
+ *
+ * @param theString The hex-encoded string to be converted into binary data (works both for upper and lowe case characters)
+ * @return binary data or nil if unsuccessful
+ */
++ (NSData *) decodeDataFromHexString: (NSString *) theString
+{
+  unsigned int stringLength = [theString length];
+  unsigned int byteLength = stringLength/2;
+  unsigned int byteCounter = 0;
+  unsigned char srcBuffer[stringLength];
+  [theString getCString:(char *)srcBuffer];
+  unsigned char *srcPtr = srcBuffer;
+  unsigned char dstBuffer[byteLength];
+  unsigned char *dst = dstBuffer;
+  while (byteCounter < byteLength)
+    {
+      unsigned char c = *srcPtr++;
+      unsigned char d = *srcPtr++;
+      unsigned hi = 0, lo = 0;
+      hi = charTo4Bits(c);
+      lo = charTo4Bits(d);
+      if (hi == 255 || lo == 255)
+        {
+          //errorCase
+          return nil;
+        }
+      dstBuffer[byteCounter++] = ((hi << 4) | lo);
+    }
+  return [NSData dataWithBytes: dst length: byteLength];
+}
+
+/**
+ * Generate a binary key which can be used for salting hashes.
+ *
+ * @param theLength length of the binary data to be generated in bytes
+ * @return Pseudo-random binary data with length theLength or nil, if an error occured
+ */
++ (NSData *) generateSaltForLength: (unsigned int) theLength
+{
+  return [NSData generateSaltForLength: theLength withBase64: NO];
+}
+
+/**
+ * Generate a binary key which can be used for salting hashes. When using
+ * with doBase64 == YES then the data will be longer than theLength
+ *
+ * @param theLength Length of the binary data to be generated in bytes
+ * @param doBase64 Convert the data into Base-64 before retuning it, be aware that this makes the binary data longer
+ * @return Pseudo-random binary data with length theLength or nil, if an error occured
+ */
++ (NSData *) generateSaltForLength: (unsigned int) theLength
+                withBase64: (BOOL) doBase64
+{
+  char *buf;
+  int fd;
+  NSData *data;
+
+  fd = open("/dev/urandom", O_RDONLY);
+
+  if (fd > 0)
+    {
+      buf = (char *)malloc(theLength);
+      read(fd, buf, theLength);
+      close(fd);
+
+      data = [NSData dataWithBytesNoCopy: buf  length: theLength  freeWhenDone: YES];
+      if(doBase64 == YES)
+        {
+          return [data dataByEncodingBase64WithLineLength: 1024];
+        }
+      return data;
+    }
+  return nil;
+}
+
+/**
+ * Encrypt/Hash the data with a given scheme
+ *
+ * @param passwordScheme The scheme to use for hashing/encryption.
+ * @param theSalt The salt to be used. If none is given but needed, it will be generated
+ * @return Binary data from the encryption by the specified scheme. On error the funciton returns nil.
+ */
+- (NSData *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+                               withSalt: (NSData *) theSalt
+{
+  if ([passwordScheme caseInsensitiveCompare: @"none"] == NSOrderedSame ||
+      [passwordScheme caseInsensitiveCompare: @"plain"] == NSOrderedSame ||
+      [passwordScheme caseInsensitiveCompare: @"cleartext"] == NSOrderedSame)
+    {
+      return self;
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
+    {
+      return [self asCryptUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"md5-crypt"] == NSOrderedSame)
+    {
+      return [self asMD5CryptUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame)
+    {
+      return [self asMD5];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
+    {
+      return [self asCramMD5];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame)
+    {
+      return [self asSMD5UsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame)
+    {
+      return [self asSHA1];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"ssha"] == NSOrderedSame)
+    {
+      return [self asSSHAUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha256"] == NSOrderedSame)
+    {
+      return [self asSHA256];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"ssha256"] == NSOrderedSame)
+    {
+      return [self asSSHA256UsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame)
+    {
+      return [self asSHA512];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame)
+    {
+      return [self asSSHA512UsingSalt: theSalt];
+    }
+  // in case the scheme was not detected, return nil
+  return nil;
+}
+
+
+/**
+ * Hash the data with MD5. Uses openssl functions to generate it
+ *
+ * @return Binary data from MD5 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asMD5
+{
+  unsigned char md5[MD5_DIGEST_LENGTH];
+  memset(md5, 0, MD5_DIGEST_LENGTH);
+
+  MD5([self bytes], [self length], md5);
+
+  return [NSData dataWithBytes: md5  length: MD5_DIGEST_LENGTH];
+}
+
+/**
+ * Hash the data with CRAM-MD5. Uses openssl functions to generate it.
+ *
+ * Note that the actual CRAM-MD5 algorithm also needs a challenge
+ * but this is not provided, this function actually calculalates
+ * only the context data which can be used for the challange-response
+ * algorithm then. This is just the underlying algorithm to store the passwords.
+ *
+ * The code is adopts the dovecot behaviour of storing the passwords
+ *
+ * @return Binary data from CRAM-MD5 'hashing'. On error the funciton returns nil.
+ */
+- (NSData *) asCramMD5
+{
+  
+  MD5_CTX ctx;
+  unsigned char inner[64];
+  unsigned char outer[64];
+  unsigned char result[32];
+  unsigned char *r;
+  int i;
+  int len;
+  NSData *key;
+  
+  if ([self length] > 64)
+    {
+      key = [self asMD5];
+    }
+  else
+    {
+      key = self;
+    }
+
+  len = [key length];
+  // fill with both inner and outer with key
+  memcpy(inner, [key bytes], len);
+  // make sure the rest of the bytes is zero
+  memset(inner + len, 0, 64 - len);
+  memcpy(outer, inner, 64);
+  
+  for (i = 0; i < 64; i++)
+    {
+      inner[i] ^= 0x36;
+      outer[i] ^= 0x5c;
+    }
+// this transformation is needed for the correct cast to binary data
+#define CDPUT(p, c) {   \
+    *p = (c) & 0xff; p++;       \
+    *p = (c) >> 8 & 0xff; p++;  \
+    *p = (c) >> 16 & 0xff; p++; \
+    *p = (c) >> 24 & 0xff; p++; \
+}
+
+  // generate first set of context bytes from outer data
+  MD5_Init(&ctx);
+  MD5_Transform(&ctx, outer);
+  r = result;
+  // convert this to correct binary data according to RFC 1321
+  CDPUT(r, ctx.A);
+  CDPUT(r, ctx.B);
+  CDPUT(r, ctx.C);
+  CDPUT(r, ctx.D);
+
+  // second set with inner data is appended to result string
+  MD5_Init(&ctx);
+  MD5_Transform(&ctx, inner);
+  // convert this to correct binary data
+  CDPUT(r, ctx.A);
+  CDPUT(r, ctx.B);
+  CDPUT(r, ctx.C);
+  CDPUT(r, ctx.D);
+
+  return [NSData dataWithBytes: result length: 32];
+}
+
+/**
+ * Hash the data with SHA1. Uses openssl functions to generate it.
+ *
+ * @return Binary data from SHA1 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asSHA1
+{
+  unsigned char sha[SHA_DIGEST_LENGTH];
+  memset(sha, 0, SHA_DIGEST_LENGTH);
+
+  SHA1([self bytes], [self length], sha);
+
+  return [NSData dataWithBytes: sha  length: SHA_DIGEST_LENGTH];
+}
+
+/**
+ * Hash the data with SHA256. Uses openssl functions to generate it.
+ *
+ * @return Binary data from SHA256 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asSHA256
+{
+  unsigned char sha[SHA256_DIGEST_LENGTH];
+  memset(sha, 0, SHA256_DIGEST_LENGTH);
+
+  SHA256([self bytes], [self length], sha);
+
+  return [NSData dataWithBytes: sha  length: SHA256_DIGEST_LENGTH];
+}
+
+/**
+ * Hash the data with SHA512. Uses openssl functions to generate it.
+ *
+ * @return Binary data from SHA512 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asSHA512
+{
+  unsigned char sha[SHA512_DIGEST_LENGTH];
+  memset(sha, 0, SHA512_DIGEST_LENGTH);
+
+  SHA512([self bytes], [self length], sha);
+
+  return [NSData dataWithBytes: sha  length: SHA512_DIGEST_LENGTH];
+}
+
+/**
+ * Hash the data with SSHA. Uses openssl functions to generate it.
+ *
+ * SSHA works following: SSHA(pass, salt) = SHA1(pass + salt) + saltData
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated
+ * @return Binary data from SHA1 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asSSHAUsingSalt: (NSData *) theSalt
+{
+  // 
+  NSMutableData *sshaData;
+
+  // generate salt, if not available
+  if ([theSalt length] == 0) theSalt = [NSData generateSaltForLength: 8];
+
+  // put the pass and salt together as one data array
+  sshaData = [NSMutableData dataWithData: self];
+  [sshaData appendData: theSalt];
+  // generate SHA1 from pass + salt
+  sshaData = [NSMutableData dataWithData: [sshaData asSHA1]];
+  // append salt again
+  [sshaData appendData: theSalt];
+
+  return sshaData;
+}
+
+/**
+ * Hash the data with SSHA256. Uses openssl functions to generate it.
+ *
+ * SSHA256 works following: SSHA256(pass, salt) = SHA256(pass + salt) + saltData
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated
+ * @return Binary data from SHA1 hashing. On error the funciton returns nil.
+ */
+
+- (NSData *) asSSHA256UsingSalt: (NSData *) theSalt
+{
+  NSMutableData *sshaData;
+
+  // generate salt, if not available
+  if ([theSalt length] == 0) theSalt = [NSData generateSaltForLength: 8];
+
+  // put the pass and salt together as one data array
+  sshaData = [NSMutableData dataWithData: self];
+  [sshaData appendData: theSalt];
+  // generate SHA1 from pass + salt
+  sshaData = [NSMutableData dataWithData: [sshaData asSHA256]];
+  // append salt again
+  [sshaData appendData: theSalt];
+
+  return sshaData;
+}
+
+/**
+ * Hash the data with SSHA512. Uses openssl functions to generate it.
+ *
+ * SSHA works following: SSHA512(pass, salt) = SHA512(pass + salt) + saltData
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated
+ * @return Binary data from SHA512 hashing. On error the funciton returns nil.
+ */
+
+- (NSData *) asSSHA512UsingSalt: (NSData *) theSalt
+{
+  NSMutableData *sshaData;
+
+  // generate salt, if not available
+  if ([theSalt length] == 0) theSalt = [NSData generateSaltForLength: 8];
+
+  // put the pass and salt together as one data array
+  sshaData = [NSMutableData dataWithData: self];
+  [sshaData appendData: theSalt];
+  // generate SHA1 from pass + salt
+  sshaData = [NSMutableData dataWithData: [sshaData asSHA512]];
+  // append salt again
+  [sshaData appendData: theSalt];
+
+  return sshaData;
+}
+
+/**
+ * Hash the data with SMD5. Uses openssl functions to generate it.
+ *
+ * SMD5 works following: SMD5(pass, salt) = MD5(pass + salt) + saltData
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated
+ * @return Binary data from SMD5 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asSMD5UsingSalt: (NSData *) theSalt
+{
+  // SMD5 works following: SMD5(pass, salt) = MD5(pass + salt) + salt
+  NSMutableData *smdData;
+
+  // generate salt, if not available
+  if ([theSalt length] == 0) theSalt = [NSData generateSaltForLength: 8];
+
+  // put the pass and salt together as one data array
+  smdData = [NSMutableData dataWithData: self];
+  [smdData appendData: theSalt];
+  // generate SHA1 from pass + salt
+  smdData = [NSMutableData dataWithData: [smdData asMD5]];
+  // append salt again
+  [smdData appendData: theSalt];
+
+  return smdData;
+}
+
+
+/**
+ * Hash the data with CRYPT-MD5 as used in /etc/passwd nowadays. Uses crypt() function to generate it.
+ *
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated. It must be printable characters only.
+ * @return Binary data from CRYPT-MD5 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asMD5CryptUsingSalt: (NSData *) theSalt
+{
+  char *buf;
+  NSMutableData *saltData;
+  NSString *cryptString;
+  NSString *saltString;
+
+  if ([theSalt length] == 0)
+    {
+      // make sure these characters are all printable by using base64
+      theSalt = [NSData generateSaltForLength: 8  withBase64: YES];
+    }
+  cryptString = [[NSString alloc] initWithData: self  encoding: NSUTF8StringEncoding];
+
+  NSString * magic = @"$1$";
+  saltData = [NSMutableData dataWithData: [magic dataUsingEncoding: NSUTF8StringEncoding]];
+  [saltData appendData: theSalt];
+  // terminate with "$"
+  [saltData appendData: [@"$" dataUsingEncoding: NSUTF8StringEncoding]];
+
+  saltString = [[NSString alloc] initWithData: saltData  encoding: NSUTF8StringEncoding];
+
+  buf = crypt([cryptString UTF8String], [saltString UTF8String]);
+  [cryptString release];
+  [saltString release];
+  if (!buf)
+    return nil;
+  return [NSData dataWithBytes: buf length: strlen(buf)];
+}
+
+/**
+ * Hash the data using crypt() function.
+ *
+ * @param theSalt The salt to be used must not be nil, if empty, one will be generated
+ * @return Binary data from CRYPT-MD5 hashing. On error the funciton returns nil.
+ */
+- (NSData *) asCryptUsingSalt: (NSData *) theSalt
+{
+  char *buf;
+  NSString *saltString;
+  NSString *cryptString;
+
+  // crypt() works with strings, so convert NSData to strings
+  cryptString = [[NSString alloc] initWithData: self  encoding: NSUTF8StringEncoding];
+
+  if ([theSalt length] == 0) theSalt = [NSData generateSaltForLength: 8 withBase64: YES];
+
+  saltString = [[NSString alloc] initWithData: theSalt  encoding: NSUTF8StringEncoding];
+
+  // The salt is weak here, but who cares anyway, crypt should not
+  // be used anymore
+  buf = crypt([cryptString UTF8String], [saltString UTF8String]);
+  [saltString release];
+  [cryptString release];
+  if (!buf)
+    return nil;
+  return [NSData dataWithBytes: buf length: strlen(buf)];
+}
+
+/**
+ * Get the salt from a password encrypted with a specied scheme
+ *
+ * @param theScheme Needed to get the salt correctly out of the pass
+ * @return The salt, if one was available in the password/scheme, else empty data
+ */
+- (NSData *) extractSalt: (NSString *) theScheme
+{
+  NSRange r;
+  int len;
+  len = [self length];
+  if (len == 0)
+    return [NSData data];
+
+  // for the ssha schemes the salt is appended at the endif
+  // so the range with the salt are bytes after each digest length
+  if ([theScheme caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
+    {
+      // for crypt schemes simply use the whole string
+      // the crypt() function is able to extract it by itself
+      r = NSMakeRange(0, len);
+    }
+  else if ([theScheme caseInsensitiveCompare: @"md5-crypt"] == NSOrderedSame)
+    {
+      // md5 crypt is generated the following "$1$<salt>$<encrypted pass>"
+      NSString *cryptString;
+      NSArray *cryptParts;
+      cryptString = [NSString stringWithUTF8String: [self bytes] ];
+      cryptParts = [cryptString componentsSeparatedByString: @"$"];
+      // correct number of elements (first one is an empty string)
+      if ([cryptParts count] != 4)
+        {
+          return [NSData data];
+        }
+      // second is the identifier of md5-crypt
+      else if( [[cryptParts objectAtIndex: 1] caseInsensitiveCompare: @"1"] != NSOrderedSame )
+        {
+          return [NSData data];
+        }
+       // third is the salt; convert it to NSData
+       return [[cryptParts objectAtIndex: 2] dataUsingEncoding: NSUTF8StringEncoding];
+    }
+  else if ([theScheme caseInsensitiveCompare: @"ssha"] == NSOrderedSame)
+    {
+      r = NSMakeRange(SHA_DIGEST_LENGTH, len - SHA_DIGEST_LENGTH);
+    }
+  else if ([theScheme caseInsensitiveCompare: @"ssha256"] == NSOrderedSame)
+    {
+      r = NSMakeRange(SHA256_DIGEST_LENGTH, len - SHA256_DIGEST_LENGTH);
+    }
+  else if ([theScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame)
+    {
+      r = NSMakeRange(SHA512_DIGEST_LENGTH, len - SHA512_DIGEST_LENGTH);
+    }
+  else if ([theScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame)
+    {
+      r = NSMakeRange(MD5_DIGEST_LENGTH, len - MD5_DIGEST_LENGTH);
+    }
+  else
+    {
+      // return empty string on unknown scheme
+      return [NSData data];
+    }
+
+  return [self subdataWithRange: r];
+}
+
+@end
+
+unsigned charTo4Bits(char c)
+{
+  unsigned bits = 0;
+  if (c > '/' && c < ':')
+    {
+      bits = c - '0';
+    }
+  else if (c > '@' && c < 'G')
+    {
+      bits = (c- 'A') + 10;
+    }
+  else if (c > '`' && c < 'g')
+    {
+      bits = (c- 'a') + 10;
+    }
+  else
+    {
+      bits = 255;
+    }
+  return bits;
+}
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSString+Crypto.h	a15042732241b52c399c8667dc0fd281f97bc131
@@ -0,0 +1,59 @@
+/* NSString+Crypto.h - this file is part of SOGo
+ *
+ * Author: Nicolas Höft
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSSTRING_CRYPTO_H
+#define NSSTRING_CRYPTO_H
+
+#import <Foundation/NSData.h>
+#import <Foundation/NSString.h>
+
+typedef enum {
+  encDefault, //!< default encoding, let the algorithm decide
+  encPlain,   //!< the data is plain text, simply convert to string
+  encHex,     //!< the data is hex encoded
+  encBase64,  //!< base64 encoding
+} keyEncoding;
+
+@class NSObject;
+
+@interface NSString (SOGoCryptoExtension)
+
+
+- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
+         withDefaultScheme: (NSString *) theScheme;
+
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+                               withSalt: (NSData *) theSalt
+                               andEncoding: (keyEncoding) encoding;
+
+// this method uses the default encoding (base64, plain, hex)
+// and generates a salt when necessary
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme;
+
+- (NSArray *) splitPasswordWithDefaultScheme: (NSString *) defaultScheme;
+
+- (NSString *) asSHA1String;
+- (NSString *) asMD5String;
+
++ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme;
+
+@end
+
+#endif /* NSSTRING_CRYPTO_H */
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSString+Crypto.m	24e1ff6773c04e588410609f312824912d333911
@@ -0,0 +1,301 @@
+/* NSString+Crypto.m - this file is part of SOGo
+ *
+ *
+ * Author: Nicolas Höft
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSValue.h>
+
+#import "NSString+Crypto.h"
+#import "NSData+Crypto.h"
+#import <NGExtensions/NGBase64Coding.h>
+
+@implementation NSString (SOGoCryptoExtension)
+
+/**
+ * Extracts the scheme from a string formed "{scheme}pass".
+ *
+ * @return The scheme or an empty string if the string did not contained a scheme in the format above
+ */
+- (NSString *) extractCryptScheme
+{
+  NSRange r;
+  int len;
+  
+  len = [self length];
+  if (len == 0)
+     return @"";
+  if ([self characterAtIndex:0] != '{')
+    return @"";
+  
+  r = [self rangeOfString:@"}" options:(NSLiteralSearch)];
+  if (r.length == 0)
+    return @"";
+  
+  r.length   = (r.location - 1);
+  r.location = 1;
+  return [[self substringWithRange:r] lowercaseString];
+}
+
+
+/**
+ * Split a password of the form {scheme}pass into an array of its components:
+ * {NSString *scheme, NString *pass, NSInteger encoding}, where encoding is
+ * the enum keyEncoding converted to an integer value.
+ *
+ * @param defaultScheme If no scheme is given in cryptedPassword, fall back to this scheme
+ * @see asCryptedPassUsingScheme
+ * @see keyEncoding
+ * @return NSArray with the three elements described above
+ */
+- (NSArray *) splitPasswordWithDefaultScheme: (NSString *) defaultScheme
+{
+  NSString *scheme;
+  NSString *pass;
+  NSArray *schemeComps;
+  keyEncoding encoding;
+  
+  NSRange range;
+  int selflen, len;
+
+  selflen = [self length];
+
+  scheme = [self extractCryptScheme];
+  len = [scheme length];
+  if (len > 0)
+    range = NSMakeRange (len+2, selflen-len-2);
+  else
+    range = NSMakeRange (0, selflen);
+  if (len == 0)
+    scheme = defaultScheme;
+
+  encoding = [NSString getDefaultEncodingForScheme: scheme];
+
+  // get the encoding which may be part of the scheme
+  // e.g. ssha.hex forces a hex encoded ssha scheme
+  // possible is "b64" or "hex"
+  schemeComps = [scheme componentsSeparatedByString: @"."];
+  if ([schemeComps count] == 2)
+    {
+      NSString *stringEncoding;
+      // scheme without encoding string is the first item
+      scheme = [schemeComps objectAtIndex: 0];
+      // encoding string is second item
+      stringEncoding = [schemeComps objectAtIndex: 1];
+      if ([stringEncoding caseInsensitiveCompare: @"hex"] == NSOrderedSame)
+        {
+          encoding = encHex;
+        }
+      else if ([stringEncoding caseInsensitiveCompare: @"b64"] == NSOrderedSame ||
+               [stringEncoding caseInsensitiveCompare: @"base64"] == NSOrderedSame)
+        {
+          encoding = encBase64;
+        }
+    }
+
+  pass = [self substringWithRange: range];
+  return [NSArray arrayWithObjects: scheme, pass, [NSNumber numberWithInt: encoding], nil];
+}
+
+/**
+ * Compare the hex or base64 encoded password with an encrypted password
+ *
+ * @param cryptedPassword The password to compare with, format {scheme}pass , "{scheme}" is optional
+ * @param theScheme If no scheme is given in cryptedPassword, fall back to this scheme
+ * @see asCryptedPassUsingScheme
+ * @return YES if the passwords are identical using this encryption scheme
+ */
+- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
+         withDefaultScheme: (NSString *) theScheme
+{
+  NSArray *passInfo;
+  NSString *selfCrypted;
+  NSString *pass;
+  NSString *scheme;
+  NSData *salt;
+  NSData *decodedData;
+  NSNumber *encodingNumber;
+  keyEncoding encoding;
+
+  // split scheme and pass
+  passInfo = [cryptedPassword splitPasswordWithDefaultScheme: theScheme];
+
+  scheme   = [passInfo objectAtIndex: 0];
+  pass     = [passInfo objectAtIndex: 1];
+  encodingNumber = [passInfo objectAtIndex: 2];
+  encoding = [encodingNumber integerValue];
+
+  if (encoding == encHex)
+    {
+      decodedData = [NSData decodeDataFromHexString: pass];
+      
+      if(decodedData == nil)
+        {
+          decodedData = [NSData data];
+        }
+      else
+       {
+          // decoding was successful, now make sure
+          // that the pass is in lowercase since decodeDataFromHexString uses
+          // lowercase charaters, too
+          pass = [pass lowercaseString];
+       }
+    }
+  else if(encoding == encBase64)
+    {
+      decodedData = [pass dataByDecodingBase64];
+      if(decodedData == nil)
+        {
+          decodedData = [NSData data];
+        }
+    }
+  else
+    {
+      decodedData = [pass dataUsingEncoding: NSUTF8StringEncoding];
+    }
+
+  salt = [decodedData extractSalt: scheme];
+
+  // encrypt self with the salt an compare the results
+  selfCrypted = [self asCryptedPassUsingScheme: scheme
+                           withSalt: salt
+                           andEncoding: encoding];
+  // return always false when there was a problem
+  if (selfCrypted == nil)
+    return NO;
+
+  if ([selfCrypted isEqualToString: pass] == YES)
+    return YES;
+  return NO;
+}
+
+/**
+ * Calls asCryptedPassUsingScheme:withSalt:andEncoding: with an empty salt and uses
+ * the default encoding.
+ *
+ * @param passwordScheme 
+ * @return If successful, the encrypted and encoded NSString of the format {scheme}pass, or nil if the scheme did not exists or an error occured
+ */
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+{
+  return [self asCryptedPassUsingScheme: passwordScheme
+                               withSalt: [NSData data]
+                            andEncoding: encDefault];
+}
+
+/**
+ * Uses NSData -asCryptedPassUsingScheme to encrypt the string and converts the
+ * binary data back to a readable string using userEncoding
+ *
+ * @param passwordScheme The scheme to use
+ * @param theSalt The binary data of the salt
+ * @param userEncoding The encoding (plain, hex, base64) to be used
+ * @return If successful, the encrypted and encoded NSString of the format {scheme}pass, or nil if the scheme did not exists or an error occured
+ */
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+                               withSalt: (NSData *) theSalt
+                          andEncoding: (keyEncoding) userEncoding
+{
+  keyEncoding dataEncoding;
+  NSData* cryptedData;
+  // convert NSString to NSData and apply encryption scheme
+  cryptedData = [self dataUsingEncoding: NSUTF8StringEncoding];
+  cryptedData = [cryptedData asCryptedPassUsingScheme: passwordScheme  withSalt: theSalt];
+  // abort on unsupported scheme or error
+  if (cryptedData == nil)
+    return nil;
+
+  // use default encoding scheme, when set to default
+  if (userEncoding == encDefault)
+    dataEncoding = [NSString getDefaultEncodingForScheme: passwordScheme];
+  else
+    dataEncoding = userEncoding;
+
+  if (dataEncoding == encHex)
+    {
+      // hex encoding
+      return [NSData encodeDataAsHexString: cryptedData];
+    }
+  else if(dataEncoding == encBase64)
+    {
+       // base64 encoding
+      NSString *s = [[NSString alloc] initWithData: [cryptedData dataByEncodingBase64WithLineLength: 1024]
+                encoding: NSASCIIStringEncoding];
+      return [s autorelease];
+    }
+
+  // plain string
+  return [[[NSString alloc] initWithData: cryptedData encoding: NSUTF8StringEncoding] autorelease];
+}
+
+/**
+ * Returns the encoding for a specified scheme
+ *
+ * @param passwordScheme The scheme for which to get the encoding.
+ * @see keyEncoding
+ * @return returns the encoding, if unknown returns encPlain
+ */
++ (keyEncoding) getDefaultEncodingForScheme: (NSString *) passwordScheme
+{
+  // in order to keep backwards-compatibility, hex encoding is used for sha1 here
+  if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
+      [passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame ||
+      [passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame ||
+      [passwordScheme caseInsensitiveCompare: @"cram-md5"] == NSOrderedSame)
+    {
+      return encHex;
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"smd5"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"ldap-md5"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"ssha"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"sha256"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"ssha256"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"ssha512"] == NSOrderedSame)
+    {
+      return encBase64;
+    }
+  return encPlain;
+}
+
+/**
+ * Encrypts the data with SHA1 scheme and returns the hex-encoded data
+ *
+ * @return If successful, sha1 encrypted and with hex encoded string
+ */
+- (NSString *) asSHA1String;
+{
+  NSData *cryptData;
+  cryptData = [self dataUsingEncoding: NSUTF8StringEncoding];
+  return [NSData encodeDataAsHexString: [cryptData asSHA1] ];
+}
+
+/**
+ * Encrypts the data with Plain MD5 scheme and returns the hex-encoded data
+ *
+ * @return If successful, MD5 encrypted and with hex encoded string
+ */
+- (NSString *) asMD5String;
+{
+  NSData *cryptData;
+  cryptData = [self dataUsingEncoding: NSUTF8StringEncoding];
+  return [NSData encodeDataAsHexString: [cryptData asMD5] ];
+}
+
+@end
============================================================
--- SoObjects/SOGo/NSString+Utilities.h	d2661ef19253d96d64dcf11127ffe6882f90b4d4
+++ SoObjects/SOGo/NSString+Utilities.h	c38d80d6ebe9592a9f2ee954282718d7265dec51
@@ -66,10 +66,6 @@
 
 - (id) objectFromJSONString;
 
-- (NSString *) asCryptStringUsingSalt: (NSString *) theSalt;
-- (NSString *) asMD5String;
-- (NSString *) asSHA1String;
-
 - (NSString *) asSafeSQLString;
 
 - (NSUInteger) countOccurrencesOfString: (NSString *) substring;
============================================================
--- SoObjects/SOGo/NSString+Utilities.m	800b97cfc8f806e14c310ed8628c94a9934fd80a
+++ SoObjects/SOGo/NSString+Utilities.m	eb4c7cd585c64cb8fb0273c3e89be36da11e5f24
@@ -21,10 +21,6 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef __OpenBSD__ 
-#include <crypt.h>
-#endif
-
 #import <Foundation/NSArray.h>
 #import <Foundation/NSCharacterSet.h>
 #import <Foundation/NSData.h>
@@ -45,12 +41,6 @@
 
 #import "NSString+Utilities.h"
 
-#define _XOPEN_SOURCE 1
-#include <unistd.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#include <openssl/sha.h>
-
 static NSMutableCharacterSet *urlNonEndingChars = nil;
 static NSMutableCharacterSet *urlAfterEndingChars = nil;
 static NSMutableCharacterSet *urlStartChars = nil;
@@ -534,48 +524,6 @@ static int cssEscapingCount;
   return object;
 }
 
-- (NSString *) asCryptStringUsingSalt: (NSString *) theSalt
-{
-  char *buf;
-  
-  // The salt is weak here, but who cares anyway, crypt should not
-  // be used anymore
-  buf = crypt([self UTF8String], [theSalt UTF8String]);
-  return [NSString stringWithUTF8String: buf];
-}
-
-- (NSString *) asMD5String
-{
-  unsigned char md[MD5_DIGEST_LENGTH];
-  char buf[80];
-  int i;
-  
-  memset(md, 0, MD5_DIGEST_LENGTH);
-  memset(buf, 0, 80);
-  
-  EVP_Digest((const void *) [self UTF8String], strlen([self UTF8String]), md, NULL, EVP_md5(), NULL);
-  for (i = 0; i < MD5_DIGEST_LENGTH; i++)
-    sprintf(&(buf[i*2]), "%02x", md[i]);
-  
-  return [NSString stringWithUTF8String: buf];
-}
-
-- (NSString *) asSHA1String
-{
-  unsigned char sha[SHA_DIGEST_LENGTH];
-  char buf[80];
-  int i;
-  
-  memset(sha, 0, SHA_DIGEST_LENGTH);
-  memset(buf, 0, 80);
-  
-  SHA1((const void *)[self UTF8String], strlen([self UTF8String]), sha);
-  for (i = 0; i < SHA_DIGEST_LENGTH; i++)
-    sprintf(&(buf[i*2]), "%02x", sha[i]);
-  
-  return [NSString stringWithUTF8String: buf];
-}
-
 - (NSString *) asSafeSQLString
 {
   return [[self stringByReplacingString: @"\\" withString: @"\\\\"]
============================================================
--- SoObjects/SOGo/SOGoUserManager.m	9bf968b36558145edd71840dd180876c1d5d7175
+++ SoObjects/SOGo/SOGoUserManager.m	344659dcdf8d929bb824d8856d05c1de85ce801e
@@ -33,6 +33,7 @@
 
 #import "NSArray+Utilities.h"
 #import "NSString+Utilities.h"
+#import "NSString+Crypto.h"
 #import "NSObject+Utilities.h"
 #import "SOGoDomainDefaults.h"
 #import "SOGoSource.h"
============================================================
--- SoObjects/SOGo/SQLSource.m	8e7fb09f6d34231ed0e1c57db516961d7a8bf0bb
+++ SoObjects/SOGo/SQLSource.m	569afbdf32cf6a95315d8e99cd910a0abaa2e9ad
@@ -39,6 +39,7 @@
 
 #import "SOGoConstants.h"
 #import "NSString+Utilities.h"
+#import "NSString+Crypto.h"
 
 #import "SQLSource.h"
 
@@ -47,7 +48,7 @@
  *
  * c_uid      - will be used for authentication - it's a username or username@domain.tld)
  * c_name     - which can be identical to c_uid - will be used to uniquely identify entries)
- * c_password - password of the user, plain-text, md5 or sha encoded for now
+ * c_password - password of the user, possible values: plain, md5, plain-md5, sha, ssha, sha256, ssha256, ssha2512, smd5, crypt, md5-crypt, cram-md5 (with or without ".hex" or ".b64" appended)
  * c_cn       - the user's common name
  * mail       - the user's mail address
  *
@@ -157,28 +158,8 @@
   if (!plainPassword || !encryptedPassword)
     return NO;
 
-  if ([_userPasswordAlgorithm caseInsensitiveCompare: @"none"] == NSOrderedSame)
-    {
-      return [plainPassword isEqualToString: encryptedPassword];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
-    {
-      return [[plainPassword asCryptStringUsingSalt: encryptedPassword] isEqualToString: encryptedPassword];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"md5"] == NSOrderedSame)
-    {
-      return [[plainPassword asMD5String] isEqualToString: encryptedPassword];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"sha"] == NSOrderedSame)
-    {
-
-      return [[plainPassword asSHA1String] isEqualToString: encryptedPassword];
-    }
-
-
-  [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
-
-  return NO;
+  return [plainPassword isEqualToCrypted: encryptedPassword
+                       withDefaultScheme: _userPasswordAlgorithm];
 }
 
 /**
@@ -189,26 +170,13 @@
  */
 - (NSString *) _encryptPassword: (NSString *) plainPassword
 {
-  if ([_userPasswordAlgorithm caseInsensitiveCompare: @"none"] == NSOrderedSame)
-    {
-      return plainPassword;
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
-    {
-      return [plainPassword asCryptStringUsingSalt: [plainPassword asMD5String]];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"md5"] == NSOrderedSame)
-    {
-      return [plainPassword asMD5String];
-    }
-  else if ([_userPasswordAlgorithm caseInsensitiveCompare: @"sha"] == NSOrderedSame)
-    {
-      return [plainPassword asSHA1String];
-    }
-  
-  [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
-  
-  return plainPassword;
+  NSString *password;
+  password = [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm];
+
+  if (password == nil)
+    [self errorWithFormat: @"Unsupported user-password algorithm: %@", _userPasswordAlgorithm];
+
+  return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm, password];
 }
 
 //
