ObjFW  Check-in [39641794dd]

Overview
Comment:Merge trunk into branch "amiga-library"
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | amiga-library
Files: files | file ages | folders
SHA3-256: 39641794dd3caa0f7d5ac63e1ea954ce5ccea080d69c0874ce7d1d1c7d4c6b07
User & Date: js on 2020-06-21 22:15:22
Other Links: branch diff | manifest | tags
Context
2020-06-21
22:26
Adjust Amiga library to new of_{pbkdf2,scrypt} API check-in: f8f3bc1545 user: js tags: amiga-library
22:15
Merge trunk into branch "amiga-library" check-in: 39641794dd user: js tags: amiga-library
22:12
Makefile: Add docs target check-in: 2dd5d682eb user: js tags: trunk
11:27
Fix missing -1 in function list of Amiga library check-in: ab7cb38e25 user: js tags: amiga-library
Changes

Modified Makefile from [c0716d54d0] to [4ae8b8a509].

8
9
10
11
12
13
14


15
16




17
18
19
20
21
22
23
24
	    config.h		\
	    config.log		\
	    config.status	\
	    extra.mk

include buildsys.mk



utils tests: src





tarball:
	echo "Generating tarball for version ${PACKAGE_VERSION}..."
	rm -fr objfw-${PACKAGE_VERSION} objfw-${PACKAGE_VERSION}.tar \
		objfw-${PACKAGE_VERSION}.tar.gz
	fossil tarball --name objfw-${PACKAGE_VERSION} current - \
		--exclude '.fossil-settings/*,.gitignore,.travis.yml' | \
		ofarc -ttgz -xq -
	cp configure config.h.in objfw-${PACKAGE_VERSION}/







>
>


>
>
>
>
|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
	    config.h		\
	    config.log		\
	    config.status	\
	    extra.mk

include buildsys.mk

.PHONY: docs tarball

utils tests: src

docs:
	rm -fr docs
	doxygen >/dev/null

tarball: docs
	echo "Generating tarball for version ${PACKAGE_VERSION}..."
	rm -fr objfw-${PACKAGE_VERSION} objfw-${PACKAGE_VERSION}.tar \
		objfw-${PACKAGE_VERSION}.tar.gz
	fossil tarball --name objfw-${PACKAGE_VERSION} current - \
		--exclude '.fossil-settings/*,.gitignore,.travis.yml' | \
		ofarc -ttgz -xq -
	cp configure config.h.in objfw-${PACKAGE_VERSION}/

Modified src/OFDNSResolver.h from [074bf54ace] to [f593d54e00].

61
62
63
64
65
66
67
68


69
70
71
72
73
74
75
	/*! The server was unable to process due to an internal error */
	OF_DNS_RESOLVER_ERROR_SERVER_FAILURE,
	/*! The server returned an error that the domain does not exist */
	OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR,
	/*! The server does not have support for the requested query */
	OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED,
	/*! The server refused the query */
	OF_DNS_RESOLVER_ERROR_SERVER_REFUSED


} of_dns_resolver_error_t;

/*!
 * @protocol OFDNSResolverQueryDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h
 *
 * @brief A delegate for performed DNS queries.
 */







|
>
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
	/*! The server was unable to process due to an internal error */
	OF_DNS_RESOLVER_ERROR_SERVER_FAILURE,
	/*! The server returned an error that the domain does not exist */
	OF_DNS_RESOLVER_ERROR_SERVER_NAME_ERROR,
	/*! The server does not have support for the requested query */
	OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED,
	/*! The server refused the query */
	OF_DNS_RESOLVER_ERROR_SERVER_REFUSED,
	/*! There was no name server to query */
	OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER
} of_dns_resolver_error_t;

/*!
 * @protocol OFDNSResolverQueryDelegate OFDNSResolver.h ObjFW/OFDNSResolver.h
 *
 * @brief A delegate for performed DNS queries.
 */

Modified src/OFDNSResolver.m from [5d30f91158] to [e0d24431d9].

814
815
816
817
818
819
820











821
822
823
824
825
826
827
	/* Random, unused ID */
	do {
		ID = [OFNumber numberWithUInt16: (uint16_t)of_random()];
	} while ([_queries objectForKey: ID] != nil);

	if (query.domainName.UTF8StringLength > 253)
		@throw [OFOutOfRangeException exception];












	context = [[[OFDNSResolverContext alloc]
	    initWithQuery: query
		       ID: ID
		 settings: _settings
		 delegate: delegate] autorelease];
	[self of_sendQueryForContext: context







>
>
>
>
>
>
>
>
>
>
>







814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
	/* Random, unused ID */
	do {
		ID = [OFNumber numberWithUInt16: (uint16_t)of_random()];
	} while ([_queries objectForKey: ID] != nil);

	if (query.domainName.UTF8StringLength > 253)
		@throw [OFOutOfRangeException exception];

	if (_settings->_nameServers.count == 0) {
		id exception = [OFDNSQueryFailedException
		    exceptionWithQuery: query
				 error: OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER];
		[delegate  resolver: self
		    didPerformQuery: query
			   response: nil
			  exception: exception];
		return;
	}

	context = [[[OFDNSResolverContext alloc]
	    initWithQuery: query
		       ID: ID
		 settings: _settings
		 delegate: delegate] autorelease];
	[self of_sendQueryForContext: context
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
				     length: BUFFER_LENGTH];
#endif

	exception = [OFDNSQueryFailedException
	    exceptionWithQuery: context->_query
			 error: OF_DNS_RESOLVER_ERROR_TIMEOUT];

	if ([context->_delegate respondsToSelector:
	    @selector(resolver:didPerformQuery:response:exception:)])
		[context->_delegate resolver: self
			     didPerformQuery: context->_query
				    response: nil
				   exception: exception];
}

- (bool)of_handleResponseBuffer: (unsigned char *)buffer
			 length: (size_t)length
			 sender: (const of_socket_address_t *)sender
{
	OFDictionary *answerRecords = nil, *authorityRecords = nil;







<
<
|
|
|
|







887
888
889
890
891
892
893


894
895
896
897
898
899
900
901
902
903
904
				     length: BUFFER_LENGTH];
#endif

	exception = [OFDNSQueryFailedException
	    exceptionWithQuery: context->_query
			 error: OF_DNS_RESOLVER_ERROR_TIMEOUT];



	[context->_delegate resolver: self
		     didPerformQuery: context->_query
			    response: nil
			   exception: exception];
}

- (bool)of_handleResponseBuffer: (unsigned char *)buffer
			 length: (size_t)length
			 sender: (const of_socket_address_t *)sender
{
	OFDictionary *answerRecords = nil, *authorityRecords = nil;
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
	} @catch (id e) {
		exception = e;
	}

	if (exception != nil)
		response = nil;

	if ([context->_delegate respondsToSelector:
	    @selector(resolver:didPerformQuery:response:exception:)])
		[context->_delegate resolver: self
			     didPerformQuery: context->_query
				    response: response
				   exception: exception];

	return false;
}

-	  (bool)socket: (OFDatagramSocket *)sock
  didReceiveIntoBuffer: (void *)buffer
		length: (size_t)length







<
<
|
|
|
|







1046
1047
1048
1049
1050
1051
1052


1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
	} @catch (id e) {
		exception = e;
	}

	if (exception != nil)
		response = nil;



	[context->_delegate resolver: self
		     didPerformQuery: context->_query
			    response: response
			   exception: exception];

	return false;
}

-	  (bool)socket: (OFDatagramSocket *)sock
  didReceiveIntoBuffer: (void *)buffer
		length: (size_t)length
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
	while ((context = [enumerator nextObject]) != nil) {
		OFDNSQueryFailedException *exception;

		exception = [OFDNSQueryFailedException
		    exceptionWithQuery: context->_query
				 error: OF_DNS_RESOLVER_ERROR_CANCELED];

		if ([context->_delegate respondsToSelector:
		    @selector(resolver:didPerformQuery:response:exception:)])
			[context->_delegate resolver: self
				     didPerformQuery: context->_query
					    response: nil
					   exception: exception];
	}

	[_queries removeAllObjects];

	objc_autoreleasePoolPop(pool);
}
@end







<
<
|
|
|
|







1278
1279
1280
1281
1282
1283
1284


1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
	while ((context = [enumerator nextObject]) != nil) {
		OFDNSQueryFailedException *exception;

		exception = [OFDNSQueryFailedException
		    exceptionWithQuery: context->_query
				 error: OF_DNS_RESOLVER_ERROR_CANCELED];



		[context->_delegate resolver: self
			     didPerformQuery: context->_query
				    response: nil
				   exception: exception];
	}

	[_queries removeAllObjects];

	objc_autoreleasePoolPop(pool);
}
@end

Modified src/exceptions/OFDNSQueryFailedException.m from [0c0fa9832e] to [1f9661bb22].

40
41
42
43
44
45
46


47
48
49
50
51
52
53
		return @"The server returned an error that the domain does not "
		    @"exist.";
	case OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED:
		return @"The server does not have support for the requested "
		    @"query.";
	case OF_DNS_RESOLVER_ERROR_SERVER_REFUSED:
		return @"The server refused the query.";


	default:
		return @"Unknown error.";
	}
}

@implementation OFDNSQueryFailedException
@synthesize query = _query, error = _error;







>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
		return @"The server returned an error that the domain does not "
		    @"exist.";
	case OF_DNS_RESOLVER_ERROR_SERVER_NOT_IMPLEMENTED:
		return @"The server does not have support for the requested "
		    @"query.";
	case OF_DNS_RESOLVER_ERROR_SERVER_REFUSED:
		return @"The server refused the query.";
	case OF_DNS_RESOLVER_ERROR_NO_NAME_SERVER:
		return @"There was no name server to query.";
	default:
		return @"Unknown error.";
	}
}

@implementation OFDNSQueryFailedException
@synthesize query = _query, error = _error;

Modified src/pbkdf2.h from [e1a5b71855] to [ca3cc52cca].

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

OF_ASSUME_NONNULL_BEGIN

/*! @file */

@class OFHMAC;





























#ifdef __cplusplus
extern "C" {
#endif
/*!
 * @brief Derives a key from a password and a salt using PBKDF2.
 *
 * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it
 *	 possible to reuse the `HMAC`, but also meaning all previous results
 *	 from the `HMAC` 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)
 * @param allowsSwappableMemory Whether data may be stored in swappable memory
 */
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, bool allowsSwappableMemory);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










<
<
<
<
|
<
<
<
<
<

|
<
<
<





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

OF_ASSUME_NONNULL_BEGIN

/*! @file */

@class OFHMAC;

/*!
 * @brief The parameters for @ref of_pbkdf2.
 */
typedef struct of_pbkdf2_parameters_t {
	/*! @brief The HMAC to use to derive a key. */
	OFHMAC *HMAC;
	/*! @brief The number of iterations to perform. */
	size_t iterations;
	/*! @brief The salt to derive a key with. */
	const unsigned char *salt;
	/*! @brief The length of the salt. */
	size_t saltLength;
	/*! @brief The password to derive a key from. */
	const char *password;
	/*! @brief The length of the password. */
	size_t passwordLength;
	/*! @brief The buffer to write the key to. */
	unsigned char *key;
	/*!
	 * @brief The desired length for the derived key.
	 *
	 * @ref key needs to have enough storage.
	 */
	size_t keyLength;
	/*! @brief Whether data may be stored in swappable memory. */
	bool allowsSwappableMemory;
} of_pbkdf2_parameters_t;

#ifdef __cplusplus
extern "C" {
#endif
/*!
 * @brief Derives a key from a password and a salt using PBKDF2.
 *
 * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it
 *	 possible to reuse the `HMAC`, but also meaning all previous results
 *	 from the `HMAC` get invalidated if they have not been copied.
 *




 * @param param The parameters to use





 */
extern void of_pbkdf2(of_pbkdf2_parameters_t param);



#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

Modified src/pbkdf2.m from [7bd85babf9] to [ae8f98e1e6].

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
103
104
105
106
107
108
109
110
111
112
113
114

#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, bool allowsSwappableMemory)
{
	void *pool = objc_autoreleasePoolPush();
	size_t blocks, digestSize = HMAC.digestSize;
	OFSecureData *buffer = [OFSecureData
		    dataWithCount: digestSize
	    allowsSwappableMemory: allowsSwappableMemory];
	OFSecureData *digest = [OFSecureData
		    dataWithCount: digestSize
	    allowsSwappableMemory: allowsSwappableMemory];
	unsigned char *bufferItems = buffer.mutableItems;
	unsigned char *digestItems = digest.mutableItems;
	OFSecureData *extendedSalt;
	unsigned char *extendedSaltItems;

	if (HMAC == nil || iterations == 0 || salt == NULL ||
	    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];

	extendedSalt = [OFSecureData dataWithCount: saltLength + 4

			     allowsSwappableMemory: allowsSwappableMemory];
	extendedSaltItems = extendedSalt.mutableItems;

	@try {
		uint32_t i = OF_BSWAP32_IF_LE(1);

		[HMAC setKey: password
		      length: passwordLength];

		memcpy(extendedSaltItems, salt, saltLength);

		while (keyLength > 0) {
			size_t length;

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

			[HMAC reset];
			[HMAC updateWithBuffer: extendedSaltItems
					length: saltLength + 4];
			memcpy(bufferItems, HMAC.digest, digestSize);
			memcpy(digestItems, HMAC.digest, digestSize);

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


				for (size_t k = 0; k < digestSize; k++)
					bufferItems[k] ^= digestItems[k];
			}

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

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

			i = OF_BSWAP32_IF_LE(OF_BSWAP32_IF_LE(i) + 1);
		}
	} @catch (id e) {
		[extendedSalt zero];
		[buffer zero];
		[digest zero];

		@throw e;
	} @finally {
		[HMAC zero];
	}

	objc_autoreleasePoolPop(pool);
}







>
|
<
<
<


|


|


|





|
|


|
|


|


|
>
|





|
|

|

|


|

|
|
|
|
|

|
|
|
|
|
>






|
|

|
|
|










|




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
103
104
105
106
107
108
109
110
111
112
113
114

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

#import "pbkdf2.h"

void
of_pbkdf2(of_pbkdf2_parameters_t param)



{
	void *pool = objc_autoreleasePoolPush();
	size_t blocks, digestSize = param.HMAC.digestSize;
	OFSecureData *buffer = [OFSecureData
		    dataWithCount: digestSize
	    allowsSwappableMemory: param.allowsSwappableMemory];
	OFSecureData *digest = [OFSecureData
		    dataWithCount: digestSize
	    allowsSwappableMemory: param.allowsSwappableMemory];
	unsigned char *bufferItems = buffer.mutableItems;
	unsigned char *digestItems = digest.mutableItems;
	OFSecureData *extendedSalt;
	unsigned char *extendedSaltItems;

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

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

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

	extendedSalt = [OFSecureData
		    dataWithCount: param.saltLength + 4
	    allowsSwappableMemory: param.allowsSwappableMemory];
	extendedSaltItems = extendedSalt.mutableItems;

	@try {
		uint32_t i = OF_BSWAP32_IF_LE(1);

		[param.HMAC setKey: param.password
			    length: param.passwordLength];

		memcpy(extendedSaltItems, param.salt, param.saltLength);

		while (param.keyLength > 0) {
			size_t length;

			memcpy(extendedSaltItems + param.saltLength, &i, 4);

			[param.HMAC reset];
			[param.HMAC updateWithBuffer: extendedSaltItems
					      length: param.saltLength + 4];
			memcpy(bufferItems, param.HMAC.digest, digestSize);
			memcpy(digestItems, param.HMAC.digest, digestSize);

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

				for (size_t k = 0; k < digestSize; k++)
					bufferItems[k] ^= digestItems[k];
			}

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

			memcpy(param.key, bufferItems, length);
			param.key += length;
			param.keyLength -= length;

			i = OF_BSWAP32_IF_LE(OF_BSWAP32_IF_LE(i) + 1);
		}
	} @catch (id e) {
		[extendedSalt zero];
		[buffer zero];
		[digest zero];

		@throw e;
	} @finally {
		[param.HMAC zero];
	}

	objc_autoreleasePoolPop(pool);
}

Modified src/runtime/exception.m from [61beb93dab] to [ff0a7a161b].

750
751
752
753
754
755
756
757

758
759
760
761
762
763
764
765
		OBJC_ERROR("Not enough memory to allocate exception!")

	e->exception.class = GNUCOBJC_EXCEPTION_CLASS;
	e->exception.cleanup = (emergency
	    ? emergencyExceptionCleanup : cleanup);
	e->object = object;

	if (_Unwind_RaiseException(&e->exception) == _URC_END_OF_STACK &&

	    uncaughtExceptionHandler != NULL)
		uncaughtExceptionHandler(object);

	OBJC_ERROR("_Unwind_RaiseException() returned!")
}

objc_uncaught_exception_handler_t
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler)







|
>
|







750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
		OBJC_ERROR("Not enough memory to allocate exception!")

	e->exception.class = GNUCOBJC_EXCEPTION_CLASS;
	e->exception.cleanup = (emergency
	    ? emergencyExceptionCleanup : cleanup);
	e->object = object;

	_Unwind_RaiseException(&e->exception);

	if (uncaughtExceptionHandler != NULL)
		uncaughtExceptionHandler(object);

	OBJC_ERROR("_Unwind_RaiseException() returned!")
}

objc_uncaught_exception_handler_t
objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t handler)

Modified src/scrypt.h from [73098e0bc6] to [2a97d56e0e].

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

OF_ASSUME_NONNULL_BEGIN

/*! @file */

@class OFHMAC;































#ifdef __cplusplus
extern "C" {
#endif
extern void of_salsa20_8_core(uint32_t buffer[_Nonnull 16]);
extern void of_scrypt_block_mix(uint32_t *output, const uint32_t *input,
    size_t blockSize);
extern void of_scrypt_romix(uint32_t *buffer, size_t blockSize,
    size_t costFactor, uint32_t *tmp);

/*!
 * @brief Derives a key from a password and a salt using scrypt.
 *
 * @param blockSize The block size to use
 * @param costFactor The CPU/memory cost factor to use
 * @param parallelization The parallelization to use
 * @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)
 * @param allowsSwappableMemory Whether data may be stored in swappable memory
 */
extern void of_scrypt(size_t blockSize, size_t costFactor,
    size_t parallelization, const unsigned char *salt, size_t saltLength,
    const char *password, size_t passwordLength,
    unsigned char *key, size_t keyLength, bool allowsSwappableMemory);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












<
<
|
<
<
<
<
<
<
<
<

|
<
<
<





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

OF_ASSUME_NONNULL_BEGIN

/*! @file */

@class OFHMAC;

/*!
 * @brief The parameters for @ref of_scrypt.
 */
typedef struct of_scrypt_parameters_t {
	/*! @brief The block size to use. */
	size_t blockSize;
	/*! @brief The CPU/memory cost factor to use. */
	size_t costFactor;
	/*! @brief The parallelization to use. */
	size_t parallelization;
	/*! @brief The salt to derive a key with. */
	const unsigned char *salt;
	/*! @brief The length of the salt. */
	size_t saltLength;
	/*! @brief The password to derive a key from. */
	const char *password;
	/*! @brief The length of the password. */
	size_t passwordLength;
	/*! @brief The buffer to write the key to. */
	unsigned char *key;
	/*!
	 * @brief The desired length for the derived key.
	 *
	 * @ref key needs to have enough storage.
	 */
	size_t keyLength;
	/*! @brief Whether data may be stored in swappable memory. */
	bool allowsSwappableMemory;
} of_scrypt_parameters_t;

#ifdef __cplusplus
extern "C" {
#endif
extern void of_salsa20_8_core(uint32_t buffer[_Nonnull 16]);
extern void of_scrypt_block_mix(uint32_t *output, const uint32_t *input,
    size_t blockSize);
extern void of_scrypt_romix(uint32_t *buffer, size_t blockSize,
    size_t costFactor, uint32_t *tmp);

/*!
 * @brief Derives a key from a password and a salt using scrypt.
 *


 * @param param The parameters to use








 */
extern void of_scrypt(of_scrypt_parameters_t param);



#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END

Modified src/scrypt.m from [bf0f4f5521] to [163ddcc8f1].

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
void
of_scrypt_block_mix(uint32_t *output, const uint32_t *input, size_t blockSize)
{
	uint32_t tmp[16];

	/* Check defined here and executed in of_scrypt() */
#define OVERFLOW_CHECK_1					\
	if (blockSize > SIZE_MAX / 2 ||				\
	    2 * blockSize - 1 > SIZE_MAX / 16)			\
		@throw [OFOutOfRangeException exception];

	memcpy(tmp, input + (2 * blockSize - 1) * 16, 64);

	for (size_t i = 0; i < 2 * blockSize; i++) {
		for (size_t j = 0; j < 16; j++)
			tmp[j] ^= input[i * 16 + j];







|
|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
void
of_scrypt_block_mix(uint32_t *output, const uint32_t *input, size_t blockSize)
{
	uint32_t tmp[16];

	/* Check defined here and executed in of_scrypt() */
#define OVERFLOW_CHECK_1					\
	if (param.blockSize > SIZE_MAX / 2 ||			\
	    2 * param.blockSize - 1 > SIZE_MAX / 16)		\
		@throw [OFOutOfRangeException exception];

	memcpy(tmp, input + (2 * blockSize - 1) * 16, 64);

	for (size_t i = 0; i < 2 * blockSize; i++) {
		for (size_t j = 0; j < 16; j++)
			tmp[j] ^= input[i * 16 + j];
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
}

void
of_scrypt_romix(uint32_t *buffer, size_t blockSize, size_t costFactor,
    uint32_t *tmp)
{
	/* Check defined here and executed in of_scrypt() */
#define OVERFLOW_CHECK_2					\
	if (blockSize > SIZE_MAX / 128 / costFactor)		\
		@throw [OFOutOfRangeException exception];

	uint32_t *tmp2 = tmp + 32 * blockSize;

	memcpy(tmp, buffer, 128 * blockSize);

	for (size_t i = 0; i < costFactor; i++) {







|
|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
}

void
of_scrypt_romix(uint32_t *buffer, size_t blockSize, size_t costFactor,
    uint32_t *tmp)
{
	/* Check defined here and executed in of_scrypt() */
#define OVERFLOW_CHECK_2						\
	if (param.blockSize > SIZE_MAX / 128 / param.costFactor)	\
		@throw [OFOutOfRangeException exception];

	uint32_t *tmp2 = tmp + 32 * blockSize;

	memcpy(tmp, buffer, 128 * blockSize);

	for (size_t i = 0; i < costFactor; i++) {
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187






188
189
190



191
192
193
194
195



196
197





198

199
200
201
202
203
204
		of_scrypt_block_mix(buffer, tmp, blockSize);

		if (i < costFactor - 1)
			memcpy(tmp, buffer, 128 * blockSize);
	}
}

void of_scrypt(size_t blockSize, size_t costFactor,
    size_t parallelization, const unsigned char *salt, size_t saltLength,
    const char *password, size_t passwordLength,
    unsigned char *key, size_t keyLength, bool allowsSwappableMemory)
{
	OFSecureData *tmp = nil, *buffer = nil;
	OFHMAC *HMAC = nil;

	if (blockSize == 0 || costFactor <= 1 ||

	    (costFactor & (costFactor - 1)) != 0 || parallelization == 0)
		@throw [OFInvalidArgumentException exception];

	/*
	 * These are defined by the functions above. They are defined there so
	 * that the check is next to the code and easy to verify, but actually
	 * checked here for performance.
	 */
	OVERFLOW_CHECK_1
	OVERFLOW_CHECK_2

	@try {
		uint32_t *tmpItems, *bufferItems;

		if (costFactor > SIZE_MAX - 1 ||
		    (costFactor + 1) > SIZE_MAX / 128)
			@throw [OFOutOfRangeException exception];

		tmp = [[OFSecureData alloc]
			 initWithItemSize: blockSize
				    count: (costFactor + 1) * 128
		    allowsSwappableMemory: allowsSwappableMemory];
		tmpItems = tmp.mutableItems;

		if (parallelization > SIZE_MAX / 128)
			@throw [OFOutOfRangeException exception];

		buffer = [[OFSecureData alloc]
			 initWithItemSize: blockSize
				    count: parallelization * 128
		    allowsSwappableMemory: allowsSwappableMemory];
		bufferItems = buffer.mutableItems;

		HMAC = [[OFHMAC alloc]
			initWithHashClass: [OFSHA256Hash class]
		    allowsSwappableMemory: allowsSwappableMemory];







		of_pbkdf2(HMAC, 1, salt, saltLength, password, passwordLength,
		    (unsigned char *)bufferItems,
		    parallelization * 128 * blockSize, allowsSwappableMemory);




		for (size_t i = 0; i < parallelization; i++)
			of_scrypt_romix(bufferItems + i * 32 * blockSize,
			    blockSize, costFactor, tmpItems);




		of_pbkdf2(HMAC, 1, (unsigned char *)bufferItems,
		    parallelization * 128 * blockSize, password, passwordLength,





		    key, keyLength, allowsSwappableMemory);

	} @finally {
		[tmp release];
		[buffer release];
		[HMAC release];
	}
}







|
|
<
<




|
>
|













|
|



|
|
|


|



|
|
|




|

>
>
>
>
>
>
|
|
|
>
>
>

|
|
|

>
>
>
|
|
>
>
>
>
>
|
>






135
136
137
138
139
140
141
142
143


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
		of_scrypt_block_mix(buffer, tmp, blockSize);

		if (i < costFactor - 1)
			memcpy(tmp, buffer, 128 * blockSize);
	}
}

void
of_scrypt(of_scrypt_parameters_t param)


{
	OFSecureData *tmp = nil, *buffer = nil;
	OFHMAC *HMAC = nil;

	if (param.blockSize == 0 || param.costFactor <= 1 ||
	    (param.costFactor & (param.costFactor - 1)) != 0 ||
	    param.parallelization == 0)
		@throw [OFInvalidArgumentException exception];

	/*
	 * These are defined by the functions above. They are defined there so
	 * that the check is next to the code and easy to verify, but actually
	 * checked here for performance.
	 */
	OVERFLOW_CHECK_1
	OVERFLOW_CHECK_2

	@try {
		uint32_t *tmpItems, *bufferItems;

		if (param.costFactor > SIZE_MAX - 1 ||
		    (param.costFactor + 1) > SIZE_MAX / 128)
			@throw [OFOutOfRangeException exception];

		tmp = [[OFSecureData alloc]
			 initWithItemSize: param.blockSize
				    count: (param.costFactor + 1) * 128
		    allowsSwappableMemory: param.allowsSwappableMemory];
		tmpItems = tmp.mutableItems;

		if (param.parallelization > SIZE_MAX / 128)
			@throw [OFOutOfRangeException exception];

		buffer = [[OFSecureData alloc]
			 initWithItemSize: param.blockSize
				    count: param.parallelization * 128
		    allowsSwappableMemory: param.allowsSwappableMemory];
		bufferItems = buffer.mutableItems;

		HMAC = [[OFHMAC alloc]
			initWithHashClass: [OFSHA256Hash class]
		    allowsSwappableMemory: param.allowsSwappableMemory];

		of_pbkdf2((of_pbkdf2_parameters_t){
			.HMAC                  = HMAC,
			.iterations            = 1,
			.salt                  = param.salt,
			.saltLength            = param.saltLength,
			.password              = param.password,
			.passwordLength        = param.passwordLength,
			.key                   = (unsigned char *)bufferItems,
			.keyLength             = param.parallelization * 128 *
			                         param.blockSize,
			.allowsSwappableMemory = param.allowsSwappableMemory
		});

		for (size_t i = 0; i < param.parallelization; i++)
			of_scrypt_romix(bufferItems + i * 32 * param.blockSize,
			    param.blockSize, param.costFactor, tmpItems);

		of_pbkdf2((of_pbkdf2_parameters_t){
			.HMAC                  = HMAC,
			.iterations            = 1,
			.salt                  = (unsigned char *)bufferItems,
			.saltLength            = param.parallelization * 128 *
			                         param.blockSize,
			.password              = param.password,
			.passwordLength        = param.passwordLength,
			.key                   = param.key,
			.keyLength             = param.keyLength,
			.allowsSwappableMemory = param.allowsSwappableMemory
		});
	} @finally {
		[tmp release];
		[buffer release];
		[HMAC release];
	}
}

Modified tests/PBKDF2Tests.m from [ce7ed4d1cb] to [1bccd3d759].

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
	OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class]
			   allowsSwappableMemory: true];
	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, true)) &&
	    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, true)) &&
	    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, true)) &&
	    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, true)) &&


	    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, true)) &&





	    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, true)) &&


	    memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7\xF0\x34"
		"\x25\xE0\xC3", 16) == 0)

	objc_autoreleasePoolPop(pool);
}
@end







>
>
>
|
>
>
>
>
>
|
|
|


>
>
>
|
>
>
>
>
>
|
|
|


>
>
>
|
>
>
>
>
>
|
|
|




>
>
>
|
>
>
>
|
>
>
|
|



|
>
>
|
>
>
|
>
>
>
>
>

|


>
>
>
|
>
>
>
|
>
>
|
|




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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class]
			   allowsSwappableMemory: true];
	unsigned char key[25];

	/* Test vectors from RFC 6070 */

	TEST(@"PBKDF2-SHA1, 1 iteration",
	    R(of_pbkdf2((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 1,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
		.passwordLength        = 8,
		.key                   = key,
		.keyLength             = 20,
		.allowsSwappableMemory = true
	    })) && 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((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 2,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
		.passwordLength        = 8,
		.key                   = key,
		.keyLength             = 20,
		.allowsSwappableMemory = true
	    })) && 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((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 4096,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
		.passwordLength        = 8,
		.key                   = key,
		.keyLength             = 20,
		.allowsSwappableMemory = true
	    })) && 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((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 16777216,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
		.passwordLength        = 8,
		.key                   = key,
		.keyLength             = 20,
		.allowsSwappableMemory = true
	    })) && 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((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 4096,
		.salt                  = (unsigned char *)"saltSALTsaltSALTsalt"
		                         "SALTsaltSALTsalt",
		.saltLength            = 36,
		.password              = "passwordPASSWORDpassword",
		.passwordLength        = 24,
		.key                   = key,
		.keyLength             = 25,
		.allowsSwappableMemory = true
	    })) &&
	    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((of_pbkdf2_parameters_t){
		.HMAC                  = HMAC,
		.iterations            = 4096,
		.salt                  = (unsigned char *)"sa\0lt",
		.saltLength            = 5,
		.password              = "pass\0word",
		.passwordLength        = 9,
		.key                   = key,
		.keyLength             = 16,
		.allowsSwappableMemory = true
	    })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7"
	        "\xF0\x34\x25\xE0\xC3", 16) == 0)

	objc_autoreleasePoolPop(pool);
}
@end

Modified tests/ScryptTests.m from [dc13eea305] to [b2b1c50b4e].

152
153
154
155
156
157
158




159






160
161
162




163






164
165
166




167

168




169
170
171
172
173




174

175




176
177
178
179
180
181

	TEST(@"ROMix",
	    R(memcpy(ROMixBuffer, ROMixInput, 128)) &&
	    R(of_scrypt_romix(ROMixBuffer, 1, 16, ROMixTmp)) &&
	    memcmp(ROMixBuffer, ROMixOutput, 128) == 0)

	TEST(@"scrypt test vector #1",




	    R(of_scrypt(1, 16, 1, (unsigned char *)"", 0, "", 0, output, 64,






	    true)) && memcmp(output, testVector1, 64) == 0)

	TEST(@"scrypt test vector #2",




	    R(of_scrypt(8, 1024, 16, (unsigned char *)"NaCl", 4, "password", 8,






	    output, 64, true)) && memcmp(output, testVector2, 64) == 0)

	TEST(@"scrypt test vector #3",




	    R(of_scrypt(8, 16384, 1, (unsigned char *)"SodiumChloride", 14,

	    "pleaseletmein", 13, output, 64, true)) &&




	    memcmp(output, testVector3, 64) == 0)

	/* The forth test vector is too expensive to include it in the tests. */
#if 0
	TEST(@"scrypt test vector #4",




	    R(of_scrypt(8, 1048576, 1, (unsigned char *)"SodiumChloride", 14,

	    "pleaseletmein", 13, output, 64, true)) &&




	    memcmp(output, testVector4, 64) == 0)
#endif

	objc_autoreleasePoolPop(pool);
}
@end







>
>
>
>
|
>
>
>
>
>
>
|


>
>
>
>
|
>
>
>
>
>
>
|


>
>
>
>
|
>
|
>
>
>
>
|




>
>
>
>
|
>
|
>
>
>
>
|





152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

	TEST(@"ROMix",
	    R(memcpy(ROMixBuffer, ROMixInput, 128)) &&
	    R(of_scrypt_romix(ROMixBuffer, 1, 16, ROMixTmp)) &&
	    memcmp(ROMixBuffer, ROMixOutput, 128) == 0)

	TEST(@"scrypt test vector #1",
	    R(of_scrypt((of_scrypt_parameters_t){
		.blockSize             = 1,
		.costFactor            = 16,
		.parallelization       = 1,
		.salt                  = (unsigned char *)"",
		.saltLength            = 0,
		.password              = "",
		.passwordLength        = 0,
		.key                   = output,
		.keyLength             = 64,
		.allowsSwappableMemory = true
	    })) && memcmp(output, testVector1, 64) == 0)

	TEST(@"scrypt test vector #2",
	    R(of_scrypt((of_scrypt_parameters_t){
		.blockSize             = 8,
		.costFactor            = 1024,
		.parallelization       = 16,
		.salt                  = (unsigned char *)"NaCl",
		.saltLength            = 4,
		.password              = "password",
		.passwordLength        = 8,
		.key                   = output,
		.keyLength             = 64,
		.allowsSwappableMemory = true
	    })) && memcmp(output, testVector2, 64) == 0)

	TEST(@"scrypt test vector #3",
	    R(of_scrypt((of_scrypt_parameters_t){
		.blockSize             = 8,
		.costFactor            = 16384,
		.parallelization       = 1,
		.salt                  = (unsigned char *)"SodiumChloride",
		.saltLength            = 14,
		.password              = "pleaseletmein",
		.passwordLength        = 13,
		.key                   = output,
		.keyLength             = 64,
		.allowsSwappableMemory = true
	    })) && memcmp(output, testVector3, 64) == 0)

	/* The forth test vector is too expensive to include it in the tests. */
#if 0
	TEST(@"scrypt test vector #4",
	    R(of_scrypt((of_scrypt_parameters_t){
		.blockSize             = 8,
		.costFactor            = 1048576,
		.parallelization       = 1,
		.salt                  = (unsigned char *)"SodiumChloride",
		.saltLength            = 14,
		.password              = "pleaseletmein",
		.passwordLength        = 13,
		.key                   = output,
		.keyLength             = 64,
		.allowsSwappableMemory = true
	    })) && memcmp(output, testVector4, 64) == 0)
#endif

	objc_autoreleasePoolPop(pool);
}
@end