ObjFW  Check-in [63f5276b33]

Overview
Comment:Move parameters for of_scrypt() to a struct

This should make it more readable for such a large number of parameters.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 63f5276b3370925ae4c8decb5f6fbf10c0334195c60797fed65bb695f053096d
User & Date: js on 2020-06-21 22:08:00
Other Links: manifest | tags
Context
2020-06-21
22:12
Makefile: Add docs target check-in: 2dd5d682eb user: js tags: trunk
22:08
Move parameters for of_scrypt() to a struct check-in: 63f5276b33 user: js tags: trunk
21:30
Move parameters for of_pbkdf2() to a struct check-in: b9641347e3 user: js tags: trunk
Changes

Modified src/pbkdf2.h from [139e147fae] to [ca3cc52cca].

47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61







-
+







	/*! @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).
	 * @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

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
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 blockSize The block size to use
 * @param costFactor The CPU/memory cost factor to use
 * @param parallelization The parallelization to use
 * @param param The parameters 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,
extern void of_scrypt(of_scrypt_parameters_t param);
    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

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

81
82
83
84
85
86
87
88
89


90
91
92
93
94
95
96
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)			\
	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
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)		\
#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
205
206
207
208
209
210
211
212
213










214
215
216
217
218
219
220
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(size_t blockSize, size_t costFactor,
    size_t parallelization, const unsigned char *salt, size_t saltLength,
void
of_scrypt(of_scrypt_parameters_t param)
    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)
	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 (costFactor > SIZE_MAX - 1 ||
		    (costFactor + 1) > SIZE_MAX / 128)
		if (param.costFactor > SIZE_MAX - 1 ||
		    (param.costFactor + 1) > SIZE_MAX / 128)
			@throw [OFOutOfRangeException exception];

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

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

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

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

		of_pbkdf2((of_pbkdf2_parameters_t){
			.HMAC = HMAC,
			.iterations = 1,
			.salt = salt,
			.saltLength = saltLength,
			.password = password,
			.passwordLength = passwordLength,
			.key = (unsigned char *)bufferItems,
			.keyLength = parallelization * 128 * blockSize,
			.allowsSwappableMemory = allowsSwappableMemory
			.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 < parallelization; i++)
			of_scrypt_romix(bufferItems + i * 32 * blockSize,
			    blockSize, costFactor, tmpItems);
		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 = parallelization * 128 * blockSize,
			.password = password,
			.passwordLength = passwordLength,
			.key = key,
			.keyLength = keyLength,
			.allowsSwappableMemory = allowsSwappableMemory
			.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 [f87038c7c8] to [1bccd3d759].

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


128
129
130
131
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







-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
+
+



-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
+
+



-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
+
+





-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
+
+




-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+



-
+



-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+

-
-
-
+
+




			   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,
		.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)
	    })) && 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,
		.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)
	    })) && 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,
		.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)
	    })) && 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,
		.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)
	    })) && 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 *)"saltSALTsaltSALTsaltSALTsaltSALTsalt",
		.saltLength = 36,
		.password = "passwordPASSWORDpassword",
		.passwordLength = 24,
		.key = key,
		.keyLength = 25,
		.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)
	        "\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,
		.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)
	    })) && 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
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,
	    R(of_scrypt(1, 16, 1, (unsigned char *)"", 0, "", 0, output, 64,
	    true)) && memcmp(output, testVector1, 64) == 0)
		.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,
	    R(of_scrypt(8, 1024, 16, (unsigned char *)"NaCl", 4, "password", 8,
	    output, 64, true)) && memcmp(output, testVector2, 64) == 0)
		.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,
	    R(of_scrypt(8, 16384, 1, (unsigned char *)"SodiumChloride", 14,
	    "pleaseletmein", 13, output, 64, true)) &&
	    memcmp(output, testVector3, 64) == 0)
		.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,
	    R(of_scrypt(8, 1048576, 1, (unsigned char *)"SodiumChloride", 14,
	    "pleaseletmein", 13, output, 64, true)) &&
	    memcmp(output, testVector4, 64) == 0)
		.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