#
# old_revision [df5dd81d62db331ba5c8de9f2257f9430c586534]
#
# add_file "SoObjects/SOGo/NSString+Crypto.h"
#  content [05c7e1f20826bdcc22933b8bac31e2d444ae2ef6]
# 
# add_file "SoObjects/SOGo/NSString+Crypto.m"
#  content [6e74b500ba1b5a864cc8b5cd13c0f2b39c226baf]
# 
# patch "SoObjects/SOGo/GNUmakefile"
#  from [9e466added539ccacaecd830173afdf9d4755802]
#    to [0a6f033637d6af50a1768f0462e2bd4fe4c6909f]
# 
# patch "SoObjects/SOGo/NSString+Utilities.h"
#  from [09d123e206a68c40e8fc0301e25d2e6052a2abf4]
#    to [ed9a551529054cdd3fb175e24db3316b24309987]
# 
# patch "SoObjects/SOGo/NSString+Utilities.m"
#  from [26a0ba2fa690ba7464585e9959c25229992a66ed]
#    to [d7e02c1a2b5633935f3fe16fd8b154e949c01c9b]
# 
# patch "SoObjects/SOGo/SQLSource.m"
#  from [3ba7f2ddd8b79c5caa63d11a0d9fea1cfe1e354a]
#    to [4544aedab94707f1aded7b4de8e5414f9b68a82f]
#
============================================================
--- SoObjects/SOGo/GNUmakefile	9e466added539ccacaecd830173afdf9d4755802
+++ SoObjects/SOGo/GNUmakefile	0a6f033637d6af50a1768f0462e2bd4fe4c6909f
@@ -46,6 +46,7 @@ SOGo_HEADER_FILES = \
 	NSObject+Utilities.h		\
 	NSString+DAV.h			\
 	NSString+Utilities.h		\
+	NSString+Crypto.h		\
 	NSURL+DAV.h			\
 	\
 	SOGoAuthenticator.h		\
@@ -114,6 +115,7 @@ SOGo_OBJC_FILES = \
 	NSObject+Utilities.m		\
 	NSString+DAV.m  		\
 	NSString+Utilities.m		\
+	NSString+Crypto.m		\
 	NSURL+DAV.m	  		\
 	\
 	SOGoSession.m			\
============================================================
--- SoObjects/SOGo/NSString+Utilities.h	09d123e206a68c40e8fc0301e25d2e6052a2abf4
+++ SoObjects/SOGo/NSString+Utilities.h	ed9a551529054cdd3fb175e24db3316b24309987
@@ -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	26a0ba2fa690ba7464585e9959c25229992a66ed
+++ SoObjects/SOGo/NSString+Utilities.m	d7e02c1a2b5633935f3fe16fd8b154e949c01c9b
@@ -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>
@@ -44,12 +40,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;
@@ -522,48 +512,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/SQLSource.m	3ba7f2ddd8b79c5caa63d11a0d9fea1cfe1e354a
+++ SoObjects/SOGo/SQLSource.m	4544aedab94707f1aded7b4de8e5414f9b68a82f
@@ -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, plain-text, md5, sha, ssha, sha256, sha2512 encoded for now
  * c_cn       - the user's common name
  * mail       - the user's mail address
  *
@@ -151,28 +152,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];
 }
 
 /**
@@ -183,26 +164,8 @@
  */
 - (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;
+  return [NSString stringWithFormat: @"{%@}%@", _userPasswordAlgorithm,
+          [plainPassword asCryptedPassUsingScheme: _userPasswordAlgorithm] ];
 }
 
 //
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSString+Crypto.h	05c7e1f20826bdcc22933b8bac31e2d444ae2ef6
@@ -0,0 +1,48 @@
+/* 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/NSString.h>
+
+@class NSObject;
+
+@interface NSString (SOGoCryptoExtension)
+- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
+         withDefaultScheme: (NSString *) theScheme;
+
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+               withSalt: (NSString*) theSalt;
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme;
+
++ (NSString *) generateSaltForLength: (unsigned int) theLength;
+- (NSArray *) splitPasswordWithDefaultScheme: (NSString *) defaultScheme;  
+
+- (NSString *) asCryptStringUsingSalt: (NSString *) theSalt;
+- (NSString *) asMD5String;
+- (NSString *) asMD5CryptStringUsingSalt: (NSString*) theSalt;
+- (NSString *) asSHA1String;
+- (NSString *) asSSHAStringUsingSalt: (NSString*) theSalt;
+- (NSString *) asSHA256String;
+- (NSString *) asSHA512String;
+@end
+
+#endif /* NSSTRING_CRYPTO_H */
============================================================
--- /dev/null	
+++ SoObjects/SOGo/NSString+Crypto.m	6e74b500ba1b5a864cc8b5cd13c0f2b39c226baf
@@ -0,0 +1,290 @@
+/* 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.
+ */
+
+#ifndef __OpenBSD__ 
+#include <crypt.h>
+#endif
+
+#import <Foundation/NSArray.h>
+
+#import "NSString+Crypto.h"
+
+#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>
+
+
+@implementation NSString (SOGoCryptoExtension)
+
++ (NSString *) generateSaltForLength: (unsigned int) theLength
+{
+  char *buf;
+  int fd;
+  int i;
+  char rnd;
+  
+  fd = open("/dev/urandom", O_RDONLY);
+
+  if (fd > 0)
+    { 
+      i = theLength;
+      buf = (char *)malloc(theLength);
+      while(--i)
+      {
+        read(fd, &rnd, 1);
+        // generate only printable characters between 32 and 94
+        buf[i] = (char)(((float)rnd / 256.)*94. + 32);
+      }
+      close(fd);
+      return [NSString stringWithUTF8String: buf];
+    }
+  return nil;
+}
+
+- (NSString *) extractCryptScheme
+{
+  NSRange r;
+  NSString* pwscheme;
+  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;
+  pwscheme = [[self substringWithRange:r] lowercaseString];
+  [pwscheme autorelease];
+  return pwscheme;
+}
+
+- (NSString *) extractSalt: (NSString *) theScheme
+{
+  if([theScheme caseInsensitiveCompare: @"crypt"] == NSOrderedSame ||
+     [theScheme caseInsensitiveCompare: @"md5-crypt"] == NSOrderedSame)
+    {
+      return self;
+    }
+  else if([theScheme caseInsensitiveCompare: @"ssha"] == NSOrderedSame)
+    {
+        return [self substringFromIndex: SHA_DIGEST_LENGTH*2];
+    }
+  return @"";
+}
+
+- (NSArray *) splitPasswordWithDefaultScheme: (NSString *) defaultScheme
+{
+  NSString *scheme;
+  NSString *pass;
+  NSString *salt;
+  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;
+
+  pass = [self substringWithRange: range];
+  salt = [pass extractSalt: scheme];
+
+  return [NSArray arrayWithObjects: scheme, pass, salt, nil];
+}
+
+
+- (BOOL) isEqualToCrypted: (NSString *) cryptedPassword
+         withDefaultScheme: (NSString *) theScheme
+{
+  NSArray *passInfo;
+  NSString *selfCrypted;
+
+  passInfo = [cryptedPassword splitPasswordWithDefaultScheme: theScheme];
+  selfCrypted = [self asCryptedPassUsingScheme: [passInfo objectAtIndex:0]
+                           withSalt: [passInfo objectAtIndex:2] ];
+  if( [selfCrypted isEqualToString: [passInfo objectAtIndex:1] ] == YES )
+    return YES;
+  return NO;
+}
+
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+{
+  return [self asCryptedPassUsingScheme: passwordScheme withSalt: @""];
+}
+
+- (NSString *) asCryptedPassUsingScheme: (NSString *) passwordScheme
+                     withSalt: (NSString*) theSalt
+{
+  if ([passwordScheme caseInsensitiveCompare: @"none"] == NSOrderedSame || 
+      [passwordScheme caseInsensitiveCompare: @"plain"] == NSOrderedSame || 
+      [passwordScheme caseInsensitiveCompare: @"cleartext"] == NSOrderedSame)
+    {
+        return self;
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"crypt"] == NSOrderedSame)
+    {
+      return [self asCryptStringUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"md5-crypt"] == NSOrderedSame)
+    {
+      return [self asMD5CryptStringUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"md5"] == NSOrderedSame ||
+           [passwordScheme caseInsensitiveCompare: @"plain-md5"] == NSOrderedSame)
+    {
+      return [self asMD5String];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha"] == NSOrderedSame)
+    {
+      return [self asSHA1String];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"ssha"] == NSOrderedSame)
+    {
+      return [self asSSHAStringUsingSalt: theSalt];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha256"] == NSOrderedSame)
+    {
+      return [self asSHA256String];
+    }
+  else if ([passwordScheme caseInsensitiveCompare: @"sha512"] == NSOrderedSame)
+    {
+      return [self asSHA512String];
+    }
+   return self;
+}
+
+- (NSString *) asCryptStringUsingSalt: (NSString *) theSalt
+{
+  if([theSalt length] == 0) theSalt = [NSString generateSaltForLength: 10];
+  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[MD5_DIGEST_LENGTH*2+1];
+  int i;
+  
+  memset(md, 0, MD5_DIGEST_LENGTH);
+  memset(buf, 0, MD5_DIGEST_LENGTH*2+1);
+  
+  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 *) asSSHAStringUsingSalt: (NSString*) theSalt
+{
+  NSString * saltedPass;
+
+  if([theSalt length] == 0) theSalt = [NSString generateSaltForLength: 10];
+
+  saltedPass = [[NSString stringWithFormat: @"%@%@", self, theSalt] asSHA1String];
+  return [NSString stringWithFormat: @"%@%@", saltedPass, theSalt];
+}
+
+- (NSString *) asSHA1String
+{
+  unsigned char sha[SHA_DIGEST_LENGTH];
+  char buf[SHA_DIGEST_LENGTH*2+1];
+  int i;
+  
+  memset(sha, 0, SHA_DIGEST_LENGTH);
+  memset(buf, 0, SHA_DIGEST_LENGTH*2+1);
+  
+  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 *) asSHA256String
+{
+  unsigned char sha[SHA256_DIGEST_LENGTH];
+  char buf[SHA256_DIGEST_LENGTH*2+1];
+  int i;
+  
+  memset(sha, 0, SHA256_DIGEST_LENGTH);
+  memset(buf, 0, SHA256_DIGEST_LENGTH*2+1);
+  
+  SHA256((const void *)[self UTF8String], strlen([self UTF8String]), sha);
+  for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
+    sprintf(&(buf[i*2]), "%02x", sha[i]);
+  
+  return [NSString stringWithUTF8String: buf];
+}
+
+- (NSString *) asSHA512String
+{
+  unsigned char sha[SHA256_DIGEST_LENGTH];
+  char buf[SHA512_DIGEST_LENGTH*2+1];
+  int i;
+
+  memset(sha, 0, SHA512_DIGEST_LENGTH);
+  memset(buf, 0, SHA512_DIGEST_LENGTH*2+1);
+
+  SHA512((const void *)[self UTF8String], strlen([self UTF8String]), sha);
+  for (i = 0; i < SHA512_DIGEST_LENGTH; i++)
+    sprintf(&(buf[i*2]), "%02x", sha[i]);
+
+  return [NSString stringWithUTF8String: buf];
+}
+
+
+- (NSString *) asMD5CryptStringUsingSalt: (NSString*) theSalt
+{
+  char *buf;
+
+  if([theSalt length] == 0)
+    theSalt = [NSString stringWithFormat: @"$1$%@$", [NSString generateSaltForLength: 10]];
+  
+  buf = crypt([self UTF8String], [theSalt UTF8String]);
+  return [NSString stringWithUTF8String: buf];
+}
+
+@end
