ObjFW  Check-in [49d1987eaf]

Overview
Comment:Implement PBKDF2
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 49d1987eaf45a854c670e6fa4326b4e5c230543d86b8f1e3b88830ff8bdcd58c
User & Date: js on 2016-07-25 22:30:49
Other Links: manifest | tags
Context
2016-07-25
22:51
Add missing files to Xcode project check-in: a5c7babba2 user: js tags: trunk
22:30
Implement PBKDF2 check-in: 49d1987eaf user: js tags: trunk
2016-07-24
20:51
OFHMAC: Allow resetting while keeping the key check-in: c55c5dff51 user: js tags: trunk
Changes

Modified src/Makefile from [40b697516a] to [6cddaa157f].

83
84
85
86
87
88
89

90
91
92
93
94
95
96
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97







+







       OFXMLProcessingInstructions.m	\
       OFZIPArchive.m			\
       OFZIPArchiveEntry.m		\
       base64.m				\
       crc32.m				\
       of_asprintf.m			\
       of_strptime.m			\
       pbkdf2.m				\
       unicode.m			\
       ${USE_SRCS_FILES}		\
       ${USE_SRCS_PLUGINS}		\
       ${USE_SRCS_SOCKETS}		\
       ${USE_SRCS_THREADS}
SRCS_FILES = OFFile.m			\
	     OFFileManager.m		\

Modified src/OFHMAC.h from [fe33092934] to [72d5a8c0be].

101
102
103
104
105
106
107








108
109
110
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118







+
+
+
+
+
+
+
+



 *	 @ref setKey:length:.
 *
 * @warning This invalidates any pointer previously returned by @ref digest. If
 *	    you are still interested in the previous digest, you need to memcpy
 *	    it yourself before calling @ref reset!
 */
- (void)reset;

/*!
 * @brief This is like @ref reset, but also zeroes the hashed key and all state.
 *
 * @warning After calling this, you *must* set a new key before reusing the
 *	    HMAC!
 */
- (void)zero;
@end

OF_ASSUME_NONNULL_END

Modified src/OFHMAC.m from [8de8a11875] to [25132018d7].

139
140
141
142
143
144
145











146
147
148
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159







+
+
+
+
+
+
+
+
+
+
+



	[_outerHash release];
	[_innerHash release];
	_outerHash = _innerHash = nil;

	_outerHash = [_outerHashCopy copy];
	_innerHash = [_innerHashCopy copy];

	_calculated = false;
}

- (void)zero
{
	[_outerHash release];
	[_innerHash release];
	[_outerHashCopy release];
	[_innerHashCopy release];
	_outerHash = _innerHash = _outerHashCopy = _innerHashCopy = nil;

	_calculated = false;
}
@end

Modified src/ObjFW.h from [99eb763c6d] to [9a3074fd4c].

200
201
202
203
204
205
206

200
201
202
203
204
205
206
207







+
#import "crc32.h"
#import "instance.h"
#import "of_asprintf.h"
#import "of_strptime.h"
#ifdef OF_HAVE_SOCKETS
# import "resolver.h"
#endif
#import "pbkdf2.h"

Added src/pbkdf2.h version [8cf4fe8ea4].






























































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS
#endif

#import "macros.h"

OF_ASSUME_NONNULL_BEGIN

/*! @file */

@class OFHMAC;

#ifdef __cplusplus
extern "C" {
#endif
/*!
 * @brief Derive a key from a password and a salt.
 *
 * @note This will call @ref OFHMAC::reset on the @ref OFHMAC first, making it
 *	 possible to reuse the @ref OFHMAC, but also meaning all previous
 *	 results from the @ref OFHMAC get invalidated if they have not been
 *	 copied.
 *
 * @param HMAC The HMAC to use to derive a key
 * @param iterations The number of iterations to perform
 * @param salt The salt to derive a key with
 * @param saltLength The length of the salt
 * @param password The password to derive a key from
 * @param passwordLength The length of the password
 * @param key The buffer to write the key to
 * @param keyLength The desired length for the derived key (key needs to have
 *		    enough storage)
 */
extern void of_pbkdf2(OFHMAC *HMAC, size_t iterations,
    const unsigned char *salt, size_t saltLength,
    const char *password, size_t passwordLength,
    unsigned char *key, size_t keyLength);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

Added src/pbkdf2.m version [e70bcecc17].







































































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <stdlib.h>

#import "OFHMAC.h"

#import "OFInvalidArgumentException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"

#import "pbkdf2.h"

void of_pbkdf2(OFHMAC *HMAC, size_t iterations,
    const unsigned char *salt, size_t saltLength,
    const char *password, size_t passwordLength,
    unsigned char *key, size_t keyLength)
{
	size_t blocks, digestSize = [HMAC digestSize];
	unsigned char *extendedSalt;
	unsigned char buffer[digestSize];
	unsigned char digest[digestSize];

	if (HMAC == nil || iterations == 0 || salt == NULL || saltLength == 0 ||
	    password == NULL || key == NULL || keyLength == 0)
		@throw [OFInvalidArgumentException exception];

	blocks = keyLength / digestSize;
	if (keyLength % digestSize != 0)
		blocks++;

	if (saltLength > SIZE_MAX - 4 || blocks > UINT32_MAX)
		@throw [OFOutOfRangeException exception];

	if ((extendedSalt = malloc(saltLength + 4)) == NULL)
		@throw [OFOutOfMemoryException
		    exceptionWithRequestedSize: saltLength + 4];

	@try {
		uint32_t i = OF_BSWAP32_IF_LE(1);

		[HMAC setKey: password
		      length: passwordLength];

		memcpy(extendedSalt, salt, saltLength);

		while (keyLength > 0) {
			size_t length;

			memcpy(extendedSalt + saltLength, &i, 4);

			[HMAC reset];
			[HMAC updateWithBuffer: extendedSalt
					length: saltLength + 4];
			memcpy(buffer, [HMAC digest], digestSize);
			memcpy(digest, [HMAC digest], digestSize);

			for (size_t j = 1; j < iterations; j++) {
				[HMAC reset];
				[HMAC updateWithBuffer: digest
						length: digestSize];
				memcpy(digest, [HMAC digest], digestSize);

				for (size_t k = 0; k < digestSize; k++)
					buffer[k] ^= digest[k];
			}

			length = digestSize;
			if (length > keyLength)
				length = keyLength;

			memcpy(key, buffer, length);
			key += length;
			keyLength -= length;

			i = OF_BSWAP32_IF_LE(OF_BSWAP32_IF_LE(i) + 1);
		}
	} @finally {
		memset(extendedSalt, 0, saltLength + 4);
		memset(buffer, 0, digestSize);
		memset(digest, 0, digestSize);

		[HMAC zero];

		free(extendedSalt);
	}
}

Modified tests/Makefile from [340c0b79d6] to [ce2c16d1ba].

22
23
24
25
26
27
28

29
30
31
32
33
34
35
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36







+







       OFSetTests.m			\
       OFStreamTests.m			\
       OFStringTests.m			\
       OFURLTests.m			\
       OFXMLElementBuilderTests.m	\
       OFXMLNodeTests.m			\
       OFXMLParserTests.m		\
       PBKDF2Tests.m			\
       RuntimeTests.m			\
       TestsAppDelegate.m		\
       ${USE_SRCS_FILES}		\
       ${USE_SRCS_PLUGINS}		\
       ${USE_SRCS_SOCKETS}		\
       ${USE_SRCS_THREADS}		\
       ${OFHTTPCLIENTTESTS_M}

Added tests/PBKDF2Tests.m version [0612a8f8d4].




















































































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016
 *   Jonathan Schleifer <js@heap.zone>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <string.h>

#import "OFHMAC.h"
#import "OFSHA1Hash.h"
#import "OFString.h"
#import "OFAutoreleasePool.h"

#import "pbkdf2.h"

#import "TestsAppDelegate.h"

static OFString *module = @"PBKDF2";

@implementation TestsAppDelegate (PBKDF2Tests)
- (void)PBKDF2Tests
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class]];
	unsigned char key[25];

	/* Test vectors from RFC 6070 */

	TEST(@"PBKDF2-SHA1, 1 iteration",
	    R(of_pbkdf2(HMAC, 1, (unsigned char*)"salt", 4, "password", 8, key,
	     20)) &&
	    memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5\x24\xAF"
		"\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0)

	TEST(@"PBKDF2-SHA1, 2 iterations",
	    R(of_pbkdf2(HMAC, 2, (unsigned char*)"salt", 4, "password", 8, key,
	    20)) &&
	    memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9\x2A\xCE"
		"\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0)

	TEST(@"PBKDF2-SHA1, 4096 iterations",
	    R(of_pbkdf2(HMAC, 4096, (unsigned char*)"salt", 4, "password", 8,
	    key, 20)) &&
	    memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49\xD9\x26"
		"\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0)

	/* This test takes too long, even on a fast machine. */
#if 0
	TEST(@"PBKDF2-SHA1, 16777216 iterations",
	    R(of_pbkdf2(HMAC, 16777216, (unsigned char*)"salt", 4, "password",
	    8, key, 20)) &&
	    memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B\x3D\x6B"
		"\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0)
#endif

	TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block",
	    R(of_pbkdf2(HMAC, 4096,
	    (unsigned char*)"saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
	    "passwordPASSWORDpassword", 24, key, 25)) &&
	    memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62"
		"\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0)

	TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block",
	    R(of_pbkdf2(HMAC, 4096, (unsigned char*)"sa\0lt", 5, "pass\0word",
	    9, key, 16)) &&
	    memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7\xF0\x34"
		"\x25\xE0\xC3", 16) == 0)

	[pool drain];
}
@end

Modified tests/TestsAppDelegate.h from [6bb325b98c] to [2f2d0cbc9c].

204
205
206
207
208
209
210




204
205
206
207
208
209
210
211
212
213
214







+
+
+
+
- (void)XMLNodeTests;
@end

@interface TestsAppDelegate (OFXMLParserTests)
    <OFXMLParserDelegate, OFXMLElementBuilderDelegate>
- (void)XMLParserTests;
@end

@interface TestsAppDelegate (PBKDF2Tests)
- (void)PBKDF2Tests;
@end

Modified tests/TestsAppDelegate.m from [60d1893094] to [fd9b7aac68].

381
382
383
384
385
386
387

388
389
390
391
392
393
394
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395







+







	[self RIPEMD160HashTests];
	[self SHA1HashTests];
	[self SHA224HashTests];
	[self SHA256HashTests];
	[self SHA384HashTests];
	[self SHA512HashTests];
	[self HMACTests];
	[self PBKDF2Tests];
	[self INIFileTests];
#endif
#ifdef OF_HAVE_SOCKETS
	[self TCPSocketTests];
	[self UDPSocketTests];
	[self kernelEventObserverTests];
#endif