1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20	File:		pbkdf2.c
21	Contains:	Apple Data Security Services PKCS #5 PBKDF2 function definition.
22	Copyright:	(C) 1999 by Apple Computer, Inc., all rights reserved
23	Written by:	Michael Brouwer <mb@apple.com>
24*/
25#include "pbkdf2.h"
26#include <string.h>
27/* Will write hLen bytes into dataPtr according to PKCS #5 2.0 spec.
28   See: http://www.rsa.com/rsalabs/node.asp?id=2127 for details.
29   tempBuffer is a pointer to at least MAX (hLen, saltLen + 4) + hLen bytes. */
30static void
31F (PRF prf, size_t hLen,
32   const void *passwordPtr, size_t passwordLen,
33   const void *saltPtr, size_t saltLen,
34   size_t iterationCount,
35   uint32_t blockNumber,
36   void *dataPtr,
37   void *tempBuffer)
38{
39	uint8_t *inBlock, *outBlock, *resultBlockPtr;
40	size_t iteration;
41	outBlock = (uint8_t*)tempBuffer;
42	inBlock = outBlock + hLen;
43	/* Set up inBlock to contain Salt || INT (blockNumber). */
44	memcpy (inBlock, saltPtr, saltLen);
45
46	inBlock[saltLen + 0] = (uint8_t)(blockNumber >> 24);
47	inBlock[saltLen + 1] = (uint8_t)(blockNumber >> 16);
48	inBlock[saltLen + 2] = (uint8_t)(blockNumber >> 8);
49	inBlock[saltLen + 3] = (uint8_t)(blockNumber);
50
51	/* Caculate U1 (result goes to outBlock) and copy it to resultBlockPtr. */
52	resultBlockPtr = (uint8_t*)dataPtr;
53	prf (passwordPtr, passwordLen, inBlock, saltLen + 4, outBlock);
54	memcpy (resultBlockPtr, outBlock, hLen);
55	/* Calculate U2 though UiterationCount. */
56	for (iteration = 2; iteration <= iterationCount; iteration++)
57	{
58		uint8_t *tempBlock;
59		uint32_t byte;
60		/* Swap inBlock and outBlock pointers. */
61		tempBlock = inBlock;
62		inBlock = outBlock;
63		outBlock = tempBlock;
64		/* Now inBlock conatins Uiteration-1.  Calculate Uiteration into outBlock. */
65		prf (passwordPtr, passwordLen, inBlock, hLen, outBlock);
66		/* Xor data in dataPtr (U1 \xor U2 \xor ... \xor Uiteration-1) with
67		   outBlock (Uiteration). */
68		for (byte = 0; byte < hLen; byte++)
69			resultBlockPtr[byte] ^= outBlock[byte];
70	}
71}
72void pbkdf2 (PRF prf, size_t hLen,
73			 const void *passwordPtr, size_t passwordLen,
74			 const void *saltPtr, size_t saltLen,
75			 size_t iterationCount,
76			 void *dkPtr, size_t dkLen,
77			 void *tempBuffer)
78{
79	size_t completeBlocks = dkLen / hLen;
80	size_t partialBlockSize = dkLen % hLen;
81	uint32_t blockNumber;
82	uint8_t *dataPtr = (uint8_t*)dkPtr;
83	uint8_t *blkBuffer = (uint8_t*)tempBuffer;
84
85    /* This check make sure that the following loops ends, in case where dk_len is 64 bits, and very large.
86     This will cause the derived key to be the maximum size supported by pbkdf2 (4GB * size of the hash)
87     rather than the actual requested size.*/
88    completeBlocks=completeBlocks & UINT32_MAX;
89
90	/* First calculate all the complete hLen sized blocks required. */
91	for (blockNumber = 1; blockNumber <= completeBlocks; blockNumber++)
92	{
93		F (prf, hLen, passwordPtr, passwordLen, saltPtr, saltLen,
94		   iterationCount, blockNumber, dataPtr, blkBuffer + hLen);
95		dataPtr += hLen;
96	}
97	/* Finally if the requested output size was not an even multiple of hLen, calculate
98	   the final block and copy the first partialBlockSize bytes of it to the output. */
99	if (partialBlockSize > 0)
100	{
101		F (prf, hLen, passwordPtr, passwordLen, saltPtr, saltLen,
102		   iterationCount, blockNumber, blkBuffer, blkBuffer + hLen);
103		memcpy (dataPtr, blkBuffer, partialBlockSize);
104	}
105}
106