From c79e3790c56e37ab4a731603716cc4331720d8d0 Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Thu, 10 Nov 2016 10:53:07 -0500 Subject: [PATCH] (feat) added sha256-crypt and sha512-crypt support --- Documentation/SOGoInstallationGuide.asciidoc | 9 ++- SoObjects/SOGo/NSData+Crypto.h | 4 +- SoObjects/SOGo/NSData+Crypto.m | 69 +++++++++++++++----- SoObjects/SOGo/NSString+Crypto.h | 2 +- SoObjects/SOGo/NSString+Crypto.m | 12 ++-- 5 files changed, 71 insertions(+), 25 deletions(-) diff --git a/Documentation/SOGoInstallationGuide.asciidoc b/Documentation/SOGoInstallationGuide.asciidoc index 94a2c0376..70c88be9e 100644 --- a/Documentation/SOGoInstallationGuide.asciidoc +++ b/Documentation/SOGoInstallationGuide.asciidoc @@ -1018,9 +1018,9 @@ be specified as a LDAP Extension in the LDAP URL (e.g. without Password Policies enabled. Possible values are: `none`, `plain`, `crypt`, `md5`, `md5-crypt`, -`smd5`, `cram-md5` and `sha`, `sha256`, `sha512` and its ssha (e.g. -`ssha` or `ssha256`) variants (plus setting of the encoding with `.b64` -or `.hex`). +`sha256-crypt` and `sha512-crypt`, `smd5`, `cram-md5` and `sha`, `sha256`, +`sha512` and its ssha (e.g. `ssha` or `ssha256`) variants +(plus setting of the encoding with `.b64` or `.hex`). For a more detailed description see http://wiki.dovecot.org/Authentication/PasswordSchemes. @@ -1029,6 +1029,9 @@ Note that `cram-md5` is not actually using cram-md5 (due to the lack of challenge-response mechanism), its just saving the intermediate MD5 context as Dovecot stores in its database. +Also note that `sha256-crypt` and `sha512-crypt` requires that your +operating system supports glibc 2.7 or more recent. + |canAuthenticate |If set to `YES`, this LDAP source is used for authentication diff --git a/SoObjects/SOGo/NSData+Crypto.h b/SoObjects/SOGo/NSData+Crypto.h index da69a40ba..d06d4fb35 100644 --- a/SoObjects/SOGo/NSData+Crypto.h +++ b/SoObjects/SOGo/NSData+Crypto.h @@ -1,7 +1,7 @@ /* NSData+Crypto.h - this file is part of SOGo * * Copyright (C) 2012 Nicolas Höft - * Copyright (C) 2012-2015 Inverse inc. + * Copyright (C) 2012-2016 Inverse inc. * * Author: Nicolas Höft * Inverse inc. @@ -44,6 +44,8 @@ - (NSData *) asSSHA256UsingSalt: (NSData *) theSalt; - (NSData *) asSHA512; - (NSData *) asSSHA512UsingSalt: (NSData *) theSalt; +- (NSData *) asSHA256CryptUsingSalt: (NSData *) theSalt; +- (NSData *) asSHA512CryptUsingSalt: (NSData *) theSalt; - (NSData *) asCramMD5; - (NSData *) asCryptUsingSalt: (NSData *) theSalt; diff --git a/SoObjects/SOGo/NSData+Crypto.m b/SoObjects/SOGo/NSData+Crypto.m index 5c0a03a06..fc4826221 100644 --- a/SoObjects/SOGo/NSData+Crypto.m +++ b/SoObjects/SOGo/NSData+Crypto.m @@ -1,7 +1,7 @@ /* NSData+Crypto.m - this file is part of SOGo * * Copyright (C) 2012 Nicolas Höft - * Copyright (C) 2012-2015 Inverse inc. + * Copyright (C) 2012-2016 Inverse inc. * Copyright (C) 2012 Jeroen Dekkers * * Author: Nicolas Höft @@ -240,6 +240,14 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input); { return [self asSSHA512UsingSalt: theSalt]; } + else if ([passwordScheme caseInsensitiveCompare: @"sha256-crypt"] == NSOrderedSame) + { + return [self asSHA256CryptUsingSalt: theSalt]; + } + else if ([passwordScheme caseInsensitiveCompare: @"sha512-crypt"] == NSOrderedSame) + { + return [self asSHA512CryptUsingSalt: theSalt]; + } // in case the scheme was not detected, return nil return nil; } @@ -581,20 +589,16 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input); 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 +// +// Internal hashing function using glibc's crypt() one. +// Glibc 2.6 supports magic == 5 and 6 +// +- (NSData *) _asCryptedUsingSalt: (NSData *) theSalt + magic: (NSString *) magic { - char *buf; + NSString *cryptString, *saltString; NSMutableData *saltData; - NSString *cryptString; - NSString *saltString; + char *buf; if ([theSalt length] == 0) { @@ -603,10 +607,10 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input); } cryptString = [[NSString alloc] initWithData: self encoding: NSUTF8StringEncoding]; - NSString * magic = @"$1$"; saltData = [NSMutableData dataWithData: [magic dataUsingEncoding: NSUTF8StringEncoding]]; [saltData appendData: theSalt]; - // terminate with "$" + + // Terminate with "$" [saltData appendData: [@"$" dataUsingEncoding: NSUTF8StringEncoding]]; saltString = [[NSString alloc] initWithData: saltData encoding: NSUTF8StringEncoding]; @@ -614,11 +618,46 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input); buf = crypt([cryptString UTF8String], [saltString UTF8String]); [cryptString release]; [saltString release]; + if (!buf) return nil; + return [NSData dataWithBytes: buf length: strlen(buf)]; } +/** + * 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 +{ + return [self _asCryptedUsingSalt: theSalt magic: @"1"]; +} + +/** + * Hash the data with CRYPT-SHA256 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-SHA256 hashing. On error the funciton returns nil. + */ +- (NSData *) asSHA256CryptUsingSalt: (NSData *) theSalt +{ + return [self _asCryptedUsingSalt: theSalt magic: @"5"]; +} + +/** + * Hash the data with CRYPT-SHA512 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-SHA512 hashing. On error the funciton returns nil. + */ +- (NSData *) asSHA512CryptUsingSalt: (NSData *) theSalt +{ + return [self _asCryptedUsingSalt: theSalt magic: @"6"]; +} + /** * Hash the data using crypt() function. * diff --git a/SoObjects/SOGo/NSString+Crypto.h b/SoObjects/SOGo/NSString+Crypto.h index ba4e23cbe..1aefd22e2 100644 --- a/SoObjects/SOGo/NSString+Crypto.h +++ b/SoObjects/SOGo/NSString+Crypto.h @@ -1,7 +1,7 @@ /* NSString+Crypto.h - this file is part of SOGo * * Copyright (C) 2012 Nicolas Höft - * Copyright (C) 2012-2015 Inverse inc. + * Copyright (C) 2012-2016 Inverse inc. * * Author: Nicolas Höft * Inverse inc. diff --git a/SoObjects/SOGo/NSString+Crypto.m b/SoObjects/SOGo/NSString+Crypto.m index bd0fa17ba..91e4fe2a0 100644 --- a/SoObjects/SOGo/NSString+Crypto.m +++ b/SoObjects/SOGo/NSString+Crypto.m @@ -129,7 +129,7 @@ { decodedData = [NSData decodeDataFromHexString: pass]; - if(decodedData == nil) + if (decodedData == nil) { decodedData = [NSData data]; } @@ -141,10 +141,10 @@ pass = [pass lowercaseString]; } } - else if(encoding == encBase64) + else if (encoding == encBase64) { decodedData = [pass dataByDecodingBase64]; - if(decodedData == nil) + if (decodedData == nil) { decodedData = [NSData data]; } @@ -158,14 +158,16 @@ // encrypt self with the salt an compare the results selfCrypted = [self asCryptedPassUsingScheme: scheme - withSalt: salt - andEncoding: encoding]; + 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; }