os/security/crypto/weakcryptospi/source/pkcs12kdf/pkcs12kdf.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/crypto/weakcryptospi/source/pkcs12kdf/pkcs12kdf.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,274 @@
     1.4 +/*
     1.5 +* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +* All rights reserved.
     1.7 +* This component and the accompanying materials are made available
     1.8 +* under the terms of the License "Eclipse Public License v1.0"
     1.9 +* which accompanies this distribution, and is available
    1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +*
    1.12 +* Initial Contributors:
    1.13 +* Nokia Corporation - initial contribution.
    1.14 +*
    1.15 +* Contributors:
    1.16 +*
    1.17 +* Description: 
    1.18 +*
    1.19 +*/
    1.20 +
    1.21 +
    1.22 +#include <hash.h>
    1.23 +#include <bigint.h>
    1.24 +#include "pkcs12kdf.h"
    1.25 +
    1.26 +
    1.27 +EXPORT_C HBufC8* PKCS12KDF::GeneratePasswordLC(const TDesC& aDes)
    1.28 +/**
    1.29 +	Convert the supplied string to a byte string, as described
    1.30 +	in SB.1 of the PKCS 12 v1.0.
    1.31 +	
    1.32 +	Each character is converted to a big endian two-byte value,
    1.33 +	and a terminating NULL character is appended to the end.
    1.34 +	
    1.35 +	@param	aDes			String to use as password.
    1.36 + */
    1.37 +	{
    1.38 +	const TInt len = aDes.Length();
    1.39 +	HBufC8* pwdBytes = HBufC8::NewMaxLC((len + 1) * 2);
    1.40 +	TPtr8 pbDes = pwdBytes->Des();
    1.41 +	
    1.42 +	TInt i = 0;
    1.43 +	while (i < len)
    1.44 +		{
    1.45 +		TUint16 ch = aDes[i];
    1.46 +		pbDes[i * 2] = ch >> 8;
    1.47 +		pbDes[(i * 2) + 1] = ch;
    1.48 +		++i;
    1.49 +		}
    1.50 +	pbDes[i * 2] = pbDes[(i * 2) + 1] = 0;
    1.51 +	
    1.52 +	return pwdBytes;
    1.53 +	}
    1.54 +
    1.55 +static TInt CeilDiv(TInt aNumerator, TInt aDenominator)
    1.56 +/**
    1.57 +	Utility function returns ceil(aNumerator / aDenominator).
    1.58 +
    1.59 +	@param	aNumerator		The numerator.
    1.60 +	@param	aDenominator	Denominator, which cannot be zero.
    1.61 +	@return					ceil(aNumerator / aDenominator)
    1.62 + */
    1.63 +	{
    1.64 +	TInt result = aNumerator / aDenominator;
    1.65 +	if ((aNumerator % aDenominator) > 0)
    1.66 +		++result;
    1.67 +	return result;
    1.68 +	}
    1.69 +
    1.70 +EXPORT_C void PKCS12KDF::DeriveKeyL(
    1.71 +	TDes8& aKey, TIDByteType aIDType,
    1.72 +	const TDesC8& aPasswd, const TDesC8& aSalt, const TUint aIterations)
    1.73 +/**
    1.74 +	Generate a key for the supplied password and salt.
    1.75 +	This implementation uses SHA1 as the hashing algorithm.
    1.76 +	
    1.77 +	@param	aKey			Descriptor which will hold key.  On entry
    1.78 +							its length must be set to the expected key length.
    1.79 +	@param	aIDType			Whether this function is being called to generate
    1.80 +							an (en|de)cryption key, an initialization vector,
    1.81 +							or a key for MAC-ing.  See SB.3 of spec.
    1.82 +	@param	aPasswd			Password string.  To comply with PKCS#12 spec,
    1.83 +							this must have 2-byte big-endian characters with
    1.84 +							a terminating null character.
    1.85 +	@param	aSalt			Used with aPasswd to generate key.
    1.86 +	@param	aIterations		Number of times to call the hash function for
    1.87 +							each block in the key.
    1.88 +	
    1.89 +	@panic	PKCS#12 16		Password is empty (debug only.)
    1.90 +	@panic	PKCS#12 17		Password does not contain an even number of bytes,
    1.91 +							and so can't use double-byte characters (debug only.)
    1.92 +	@panic	PKCS#12 18		The final two-byte character is not a null terminator,
    1.93 +							or a null terminator occurs before the end (debug only.)
    1.94 + */
    1.95 +	{
    1.96 +	__ASSERT_DEBUG(aPasswd.Length() >= 2, Panic(EDKEmptyPswd));
    1.97 +	__ASSERT_DEBUG((aPasswd.Length() % 2) == 0, Panic(EDKOddPswdByteCount));
    1.98 +	TInt useCharCount = aPasswd.Length() / 2;
    1.99 +	TPtrC16 pswd16(reinterpret_cast<const TUint16*>(aPasswd.Ptr()), useCharCount);
   1.100 +	TInt nullPos = pswd16.Locate(L'\0');
   1.101 +	__ASSERT_DEBUG(nullPos == (useCharCount - 1), Panic(EDKBadNullTerminator));
   1.102 +
   1.103 +	// use the same notation as the standard
   1.104 +	const TUint8 ID = static_cast<TUint8>(aIDType);
   1.105 +	const TInt u = 160;					// chaining variable length for SHA-1
   1.106 +	const TInt v = 512;					// message input length for SHA-1
   1.107 +	const TInt n = aKey.Length() * 8;	// number of bits required in key
   1.108 +	const TInt p = aPasswd.Length();
   1.109 +	const TInt s = aSalt.Length();
   1.110 +	const TInt r = aIterations;
   1.111 +	
   1.112 +	// (numbered steps are from the standard)
   1.113 +	// 1. Construct a string, D (the "diversifier"), by concatenating
   1.114 +	// v/8 copies of ID.
   1.115 +	const TInt D_LEN = v / 8;
   1.116 +	HBufC8* D_ = HBufC8::NewMaxLC(D_LEN);
   1.117 +	TPtr8 D = D_->Des();
   1.118 +	D.Fill(ID);
   1.119 +	
   1.120 +	// 2. Concatenate copies of the salt together to create a string S
   1.121 +	// of length v * ceil(s/v) bits (the final copy of the salt may be
   1.122 +	// truncated to create S).  Note that if the salt is the empty string,
   1.123 +	// then so is S.
   1.124 +	const TInt S_OVER_V_CEIL = CeilDiv(s, v);
   1.125 +	const TInt S_LEN = (v * S_OVER_V_CEIL) / 8;
   1.126 +	HBufC8* S_ = HBufC8::NewMaxLC(S_LEN);
   1.127 +	TPtr8 S = S_->Des();
   1.128 +	S.Repeat(aSalt);
   1.129 +	
   1.130 +	// 3. Concatenate copies of the password together to create a string P
   1.131 +	// of length v * ceil(p/v) bits (the final copy of the password may be
   1.132 +	// truncated to create P).  Note that if the password is the empty string
   1.133 +	// then so is P.
   1.134 +	const TInt P_OVER_V_CEIL = CeilDiv(p, v);
   1.135 +	const TInt P_LEN = (v * P_OVER_V_CEIL) / 8;
   1.136 +	HBufC8* P_ = HBufC8::NewMaxLC(P_LEN);
   1.137 +	TPtr8 P = P_->Des();
   1.138 +	P.Repeat(aPasswd);
   1.139 +	
   1.140 +	// 4. Set I=S||P to be the concatenation of S and P.
   1.141 +	const TInt I_LEN = S_LEN + P_LEN;
   1.142 +	HBufC8* I_ = HBufC8::NewLC(I_LEN);
   1.143 +	TPtr8 I = I_->Des();
   1.144 +	I.Copy(S);
   1.145 +	I.Append(P);
   1.146 +	
   1.147 +	// 5. Set c=ceil(n/u).
   1.148 +	const TInt c = CeilDiv(n, u);
   1.149 +	
   1.150 +	// ahead 7: allocate result buffer A
   1.151 +	// (Each Ai has SHA1_HASH bytes.)
   1.152 +	HBufC8* A_ = HBufC8::NewLC(c * SHA1_HASH);
   1.153 +	TPtr8 A = A_->Des();
   1.154 +	
   1.155 +	// 6. For i=1, 2, ..., c, do the following
   1.156 +	
   1.157 +	// pre-allocate SHA1 object, DI, and B buffers
   1.158 +	CSHA1* sha1 = CSHA1::NewL();
   1.159 +	CleanupStack::PushL(sha1);
   1.160 +	
   1.161 +	const TInt DI_LEN = D_LEN + I_LEN;
   1.162 +	HBufC8* DI_ = HBufC8::NewLC(DI_LEN);
   1.163 +	TPtr8 DI = DI_->Des();
   1.164 +	
   1.165 +	const TInt B_LEN = v / 8;
   1.166 +	HBufC8* B_ = HBufC8::NewMaxLC(B_LEN);
   1.167 +	TPtr8 B = B_->Des();
   1.168 +	
   1.169 +	for (TInt i = 1; i <= c; ++i)
   1.170 +		{
   1.171 +		// 6a) Set Ai = H^r(D||I).  (i.e. the rth hash of D||I,
   1.172 +		// H(H(H(...H(D||I))))
   1.173 +		DI.Copy(D);
   1.174 +		DI.Append(I);
   1.175 +		
   1.176 +		sha1->Reset();
   1.177 +		TBuf8<SHA1_HASH> Ai(sha1->Final(DI));
   1.178 +		
   1.179 +		for (TInt iterCount = 2; iterCount <= r; ++iterCount)
   1.180 +			{
   1.181 +			Ai.Copy(sha1->Final(Ai));
   1.182 +			}
   1.183 +		
   1.184 +		// 6b) Concatenate copies of Ai to create a string B of length
   1.185 +		// v bits (the final copy of Ai may be truncated to create B).
   1.186 +		B.Repeat(Ai);
   1.187 +		
   1.188 +		// 6c) Treating I as a concatenation I0, I1, ..., Ik-1 of
   1.189 +		// v-bit blocks, where k=ceil(s/v)+ceil(p/v), modify I by
   1.190 +		// setting Ij=(Ij+B+1) mod 2^v for each j.
   1.191 +
   1.192 +		const TInt k = S_OVER_V_CEIL + P_OVER_V_CEIL;
   1.193 +		for (TInt j = 0; j < k; ++j)
   1.194 +			{
   1.195 +			TPtr8 section = I.MidTPtr((v/8) * j, v/8);
   1.196 +			Process6cL(section, B, v);
   1.197 +			}
   1.198 +		
   1.199 +		// 7. Concatenate A1, A2, ..., Ac together to form a pseudo-random
   1.200 +		// bit string, A.
   1.201 +		A.Append(Ai);
   1.202 +		
   1.203 +		// stop building A if already have enough bits for key
   1.204 +		if (A.Length() >= n / 8)
   1.205 +			break;
   1.206 +		}
   1.207 +
   1.208 +	// Use the first n bits of A as the output of this entire process.
   1.209 +	aKey.Copy(A.Left(n / 8));
   1.210 +	
   1.211 +	CleanupStack::PopAndDestroy(8, D_);	// B_, DI_, sha1, A_, I_, P_, S_, D_
   1.212 +	}
   1.213 +
   1.214 +void PKCS12KDF::Process6cL(TDes8& Ij, const TDesC8& B, TInt v)
   1.215 +/**
   1.216 +	Helper function for DeriveKeyL modifies part of I,
   1.217 +	as described in step 6c of SB.2.
   1.218 +	
   1.219 +	@param	Ij		Section of I (S || P).
   1.220 +	@param	B		rth hash of D || I.
   1.221 +	@param	v		Number of bits to preserve in result.
   1.222 + */
   1.223 +	{
   1.224 +	// 6c) Treating I as a concatenation I0, I1, ..., Ik-1 of
   1.225 +	// v-bit blocks, where k=ceil(s/v)+ceil(p/v), modify I by
   1.226 +	// setting Ij=(Ij+B+1) mod 2^v for each j.
   1.227 +	
   1.228 +	RInteger RI_Ij = RInteger::NewL(Ij);
   1.229 +	TCleanupItem ciIj = RI_Ij;
   1.230 +	CleanupStack::PushL(ciIj);
   1.231 +	
   1.232 +	RInteger RI_B = RInteger::NewL(B);
   1.233 +	TCleanupItem ciB = RI_B;
   1.234 +	CleanupStack::PushL(ciB);
   1.235 +	
   1.236 +	// these additions can leave
   1.237 +	RI_Ij += RI_B;
   1.238 +	RI_Ij += 1;
   1.239 +	
   1.240 +	HBufC8* result = RI_Ij.BufferLC();
   1.241 +	
   1.242 +	Ij.Zero();
   1.243 +	TInt resultLen = result->Length();
   1.244 +	
   1.245 +	TInt bytesToPreserve = v / 8;
   1.246 +	TInt leadingZeroes = bytesToPreserve - resultLen;
   1.247 +	if (leadingZeroes <= 0)
   1.248 +		Ij.Copy(result->Right(bytesToPreserve));
   1.249 +	else
   1.250 +		{
   1.251 +		Ij.FillZ(leadingZeroes);
   1.252 +		Ij.Append(*result);
   1.253 +		}
   1.254 +	
   1.255 +	CleanupStack::PopAndDestroy(3, &RI_Ij);	// result, ciB, ciIj
   1.256 +	}
   1.257 +
   1.258 +#ifdef _DEBUG
   1.259 +
   1.260 +void PKCS12KDF::Panic(PKCS12KDF::TPanic aPanic)
   1.261 +/**
   1.262 +	This function is used in debug builds to halt
   1.263 +	the current thread when a logic error is detected.
   1.264 +	
   1.265 +	The current thread is panicked with category "PKCS12KDF"
   1.266 +	and the supplied reason.
   1.267 +	
   1.268 +	@param	aPanic			Converted to numeric value and
   1.269 +							used for the panic reason.
   1.270 + */
   1.271 +	{
   1.272 +	_LIT(KPanicCat, "PKCS12KDF");
   1.273 +	User::Panic(KPanicCat, aPanic);
   1.274 +	}
   1.275 +
   1.276 +#endif
   1.277 +