(feat) added sha256-crypt and sha512-crypt support

pull/230/head
Ludovic Marcotte 2016-11-10 10:53:07 -05:00
parent dc70e7e691
commit c79e3790c5
5 changed files with 71 additions and 25 deletions

View File

@ -1018,9 +1018,9 @@ be specified as a LDAP Extension in the LDAP URL (e.g.
without Password Policies enabled. without Password Policies enabled.
Possible values are: `none`, `plain`, `crypt`, `md5`, `md5-crypt`, Possible values are: `none`, `plain`, `crypt`, `md5`, `md5-crypt`,
`smd5`, `cram-md5` and `sha`, `sha256`, `sha512` and its ssha (e.g. `sha256-crypt` and `sha512-crypt`, `smd5`, `cram-md5` and `sha`, `sha256`,
`ssha` or `ssha256`) variants (plus setting of the encoding with `.b64` `sha512` and its ssha (e.g. `ssha` or `ssha256`) variants
or `.hex`). (plus setting of the encoding with `.b64` or `.hex`).
For a more detailed description see For a more detailed description see
http://wiki.dovecot.org/Authentication/PasswordSchemes. 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 challenge-response mechanism), its just saving the intermediate MD5
context as Dovecot stores in its database. 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 |canAuthenticate
|If set to `YES`, this LDAP source is used for authentication |If set to `YES`, this LDAP source is used for authentication

View File

@ -1,7 +1,7 @@
/* NSData+Crypto.h - this file is part of SOGo /* NSData+Crypto.h - this file is part of SOGo
* *
* Copyright (C) 2012 Nicolas Höft * Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012-2015 Inverse inc. * Copyright (C) 2012-2016 Inverse inc.
* *
* Author: Nicolas Höft * Author: Nicolas Höft
* Inverse inc. * Inverse inc.
@ -44,6 +44,8 @@
- (NSData *) asSSHA256UsingSalt: (NSData *) theSalt; - (NSData *) asSSHA256UsingSalt: (NSData *) theSalt;
- (NSData *) asSHA512; - (NSData *) asSHA512;
- (NSData *) asSSHA512UsingSalt: (NSData *) theSalt; - (NSData *) asSSHA512UsingSalt: (NSData *) theSalt;
- (NSData *) asSHA256CryptUsingSalt: (NSData *) theSalt;
- (NSData *) asSHA512CryptUsingSalt: (NSData *) theSalt;
- (NSData *) asCramMD5; - (NSData *) asCramMD5;
- (NSData *) asCryptUsingSalt: (NSData *) theSalt; - (NSData *) asCryptUsingSalt: (NSData *) theSalt;

View File

@ -1,7 +1,7 @@
/* NSData+Crypto.m - this file is part of SOGo /* NSData+Crypto.m - this file is part of SOGo
* *
* Copyright (C) 2012 Nicolas Höft * Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012-2015 Inverse inc. * Copyright (C) 2012-2016 Inverse inc.
* Copyright (C) 2012 Jeroen Dekkers * Copyright (C) 2012 Jeroen Dekkers
* *
* Author: Nicolas Höft * Author: Nicolas Höft
@ -240,6 +240,14 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
{ {
return [self asSSHA512UsingSalt: theSalt]; 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 // in case the scheme was not detected, return nil
return nil; return nil;
} }
@ -581,20 +589,16 @@ static void _nettle_md5_compress(uint32_t *digest, const uint8_t *input);
return smdData; return smdData;
} }
//
/** // Internal hashing function using glibc's crypt() one.
* Hash the data with CRYPT-MD5 as used in /etc/passwd nowadays. Uses crypt() function to generate it. // Glibc 2.6 supports magic == 5 and 6
* //
* - (NSData *) _asCryptedUsingSalt: (NSData *) theSalt
* @param theSalt The salt to be used must not be nil, if empty, one will be generated. It must be printable characters only. magic: (NSString *) magic
* @return Binary data from CRYPT-MD5 hashing. On error the funciton returns nil.
*/
- (NSData *) asMD5CryptUsingSalt: (NSData *) theSalt
{ {
char *buf; NSString *cryptString, *saltString;
NSMutableData *saltData; NSMutableData *saltData;
NSString *cryptString; char *buf;
NSString *saltString;
if ([theSalt length] == 0) 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]; cryptString = [[NSString alloc] initWithData: self encoding: NSUTF8StringEncoding];
NSString * magic = @"$1$";
saltData = [NSMutableData dataWithData: [magic dataUsingEncoding: NSUTF8StringEncoding]]; saltData = [NSMutableData dataWithData: [magic dataUsingEncoding: NSUTF8StringEncoding]];
[saltData appendData: theSalt]; [saltData appendData: theSalt];
// terminate with "$"
// Terminate with "$"
[saltData appendData: [@"$" dataUsingEncoding: NSUTF8StringEncoding]]; [saltData appendData: [@"$" dataUsingEncoding: NSUTF8StringEncoding]];
saltString = [[NSString alloc] initWithData: saltData encoding: 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]); buf = crypt([cryptString UTF8String], [saltString UTF8String]);
[cryptString release]; [cryptString release];
[saltString release]; [saltString release];
if (!buf) if (!buf)
return nil; return nil;
return [NSData dataWithBytes: buf length: strlen(buf)]; 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. * Hash the data using crypt() function.
* *

View File

@ -1,7 +1,7 @@
/* NSString+Crypto.h - this file is part of SOGo /* NSString+Crypto.h - this file is part of SOGo
* *
* Copyright (C) 2012 Nicolas Höft * Copyright (C) 2012 Nicolas Höft
* Copyright (C) 2012-2015 Inverse inc. * Copyright (C) 2012-2016 Inverse inc.
* *
* Author: Nicolas Höft * Author: Nicolas Höft
* Inverse inc. * Inverse inc.

View File

@ -129,7 +129,7 @@
{ {
decodedData = [NSData decodeDataFromHexString: pass]; decodedData = [NSData decodeDataFromHexString: pass];
if(decodedData == nil) if (decodedData == nil)
{ {
decodedData = [NSData data]; decodedData = [NSData data];
} }
@ -141,10 +141,10 @@
pass = [pass lowercaseString]; pass = [pass lowercaseString];
} }
} }
else if(encoding == encBase64) else if (encoding == encBase64)
{ {
decodedData = [pass dataByDecodingBase64]; decodedData = [pass dataByDecodingBase64];
if(decodedData == nil) if (decodedData == nil)
{ {
decodedData = [NSData data]; decodedData = [NSData data];
} }
@ -158,14 +158,16 @@
// encrypt self with the salt an compare the results // encrypt self with the salt an compare the results
selfCrypted = [self asCryptedPassUsingScheme: scheme selfCrypted = [self asCryptedPassUsingScheme: scheme
withSalt: salt withSalt: salt
andEncoding: encoding]; andEncoding: encoding];
// return always false when there was a problem // return always false when there was a problem
if (selfCrypted == nil) if (selfCrypted == nil)
return NO; return NO;
if ([selfCrypted isEqualToString: pass] == YES) if ([selfCrypted isEqualToString: pass] == YES)
return YES; return YES;
return NO; return NO;
} }