crypto/weakcrypto/source/pkcs12kdf/pkcs12kdf.cpp
changeset 72 de46a57f75fb
equal deleted inserted replaced
65:970c0057d9bc 72:de46a57f75fb
       
     1 /*
       
     2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <hash.h>
       
    20 #include <bigint.h>
       
    21 #include "pkcs12kdf.h"
       
    22 
       
    23 
       
    24 EXPORT_C HBufC8* PKCS12KDF::GeneratePasswordLC(const TDesC& aDes)
       
    25 /**
       
    26 	Convert the supplied string to a byte string, as described
       
    27 	in SB.1 of the PKCS 12 v1.0.
       
    28 	
       
    29 	Each character is converted to a big endian two-byte value,
       
    30 	and a terminating NULL character is appended to the end.
       
    31 	
       
    32 	@param	aDes			String to use as password.
       
    33  */
       
    34 	{
       
    35 	const TInt len = aDes.Length();
       
    36 	HBufC8* pwdBytes = HBufC8::NewMaxLC((len + 1) * 2);
       
    37 	TPtr8 pbDes = pwdBytes->Des();
       
    38 	
       
    39 	TInt i = 0;
       
    40 	while (i < len)
       
    41 		{
       
    42 		TUint16 ch = aDes[i];
       
    43 		pbDes[i * 2] = ch >> 8;
       
    44 		pbDes[(i * 2) + 1] = ch;
       
    45 		++i;
       
    46 		}
       
    47 	pbDes[i * 2] = pbDes[(i * 2) + 1] = 0;
       
    48 	
       
    49 	return pwdBytes;
       
    50 	}
       
    51 
       
    52 static TInt CeilDiv(TInt aNumerator, TInt aDenominator)
       
    53 /**
       
    54 	Utility function returns ceil(aNumerator / aDenominator).
       
    55 
       
    56 	@param	aNumerator		The numerator.
       
    57 	@param	aDenominator	Denominator, which cannot be zero.
       
    58 	@return					ceil(aNumerator / aDenominator)
       
    59  */
       
    60 	{
       
    61 	TInt result = aNumerator / aDenominator;
       
    62 	if ((aNumerator % aDenominator) > 0)
       
    63 		++result;
       
    64 	return result;
       
    65 	}
       
    66 
       
    67 EXPORT_C void PKCS12KDF::DeriveKeyL(
       
    68 	TDes8& aKey, TIDByteType aIDType,
       
    69 	const TDesC8& aPasswd, const TDesC8& aSalt, const TUint aIterations)
       
    70 /**
       
    71 	Generate a key for the supplied password and salt.
       
    72 	This implementation uses SHA1 as the hashing algorithm.
       
    73 	
       
    74 	@param	aKey			Descriptor which will hold key.  On entry
       
    75 							its length must be set to the expected key length.
       
    76 	@param	aIDType			Whether this function is being called to generate
       
    77 							an (en|de)cryption key, an initialization vector,
       
    78 							or a key for MAC-ing.  See SB.3 of spec.
       
    79 	@param	aPasswd			Password string.  To comply with PKCS#12 spec,
       
    80 							this must have 2-byte big-endian characters with
       
    81 							a terminating null character.
       
    82 	@param	aSalt			Used with aPasswd to generate key.
       
    83 	@param	aIterations		Number of times to call the hash function for
       
    84 							each block in the key.
       
    85 	
       
    86 	@panic	PKCS#12 16		Password is empty (debug only.)
       
    87 	@panic	PKCS#12 17		Password does not contain an even number of bytes,
       
    88 							and so can't use double-byte characters (debug only.)
       
    89 	@panic	PKCS#12 18		The final two-byte character is not a null terminator,
       
    90 							or a null terminator occurs before the end (debug only.)
       
    91  */
       
    92 	{
       
    93 	__ASSERT_DEBUG(aPasswd.Length() >= 2, Panic(EDKEmptyPswd));
       
    94 	__ASSERT_DEBUG((aPasswd.Length() % 2) == 0, Panic(EDKOddPswdByteCount));
       
    95 	TInt useCharCount = aPasswd.Length() / 2;
       
    96 	TPtrC16 pswd16(reinterpret_cast<const TUint16*>(aPasswd.Ptr()), useCharCount);
       
    97 	TInt nullPos = pswd16.Locate(L'\0');
       
    98 	__ASSERT_DEBUG(nullPos == (useCharCount - 1), Panic(EDKBadNullTerminator));
       
    99 
       
   100 	// use the same notation as the standard
       
   101 	const TUint8 ID = static_cast<TUint8>(aIDType);
       
   102 	const TInt u = 160;					// chaining variable length for SHA-1
       
   103 	const TInt v = 512;					// message input length for SHA-1
       
   104 	const TInt n = aKey.Length() * 8;	// number of bits required in key
       
   105 	const TInt p = aPasswd.Length();
       
   106 	const TInt s = aSalt.Length();
       
   107 	const TInt r = aIterations;
       
   108 	
       
   109 	// (numbered steps are from the standard)
       
   110 	// 1. Construct a string, D (the "diversifier"), by concatenating
       
   111 	// v/8 copies of ID.
       
   112 	const TInt D_LEN = v / 8;
       
   113 	HBufC8* D_ = HBufC8::NewMaxLC(D_LEN);
       
   114 	TPtr8 D = D_->Des();
       
   115 	D.Fill(ID);
       
   116 	
       
   117 	// 2. Concatenate copies of the salt together to create a string S
       
   118 	// of length v * ceil(s/v) bits (the final copy of the salt may be
       
   119 	// truncated to create S).  Note that if the salt is the empty string,
       
   120 	// then so is S.
       
   121 	const TInt S_OVER_V_CEIL = CeilDiv(s, v);
       
   122 	const TInt S_LEN = (v * S_OVER_V_CEIL) / 8;
       
   123 	HBufC8* S_ = HBufC8::NewMaxLC(S_LEN);
       
   124 	TPtr8 S = S_->Des();
       
   125 	S.Repeat(aSalt);
       
   126 	
       
   127 	// 3. Concatenate copies of the password together to create a string P
       
   128 	// of length v * ceil(p/v) bits (the final copy of the password may be
       
   129 	// truncated to create P).  Note that if the password is the empty string
       
   130 	// then so is P.
       
   131 	const TInt P_OVER_V_CEIL = CeilDiv(p, v);
       
   132 	const TInt P_LEN = (v * P_OVER_V_CEIL) / 8;
       
   133 	HBufC8* P_ = HBufC8::NewMaxLC(P_LEN);
       
   134 	TPtr8 P = P_->Des();
       
   135 	P.Repeat(aPasswd);
       
   136 	
       
   137 	// 4. Set I=S||P to be the concatenation of S and P.
       
   138 	const TInt I_LEN = S_LEN + P_LEN;
       
   139 	HBufC8* I_ = HBufC8::NewLC(I_LEN);
       
   140 	TPtr8 I = I_->Des();
       
   141 	I.Copy(S);
       
   142 	I.Append(P);
       
   143 	
       
   144 	// 5. Set c=ceil(n/u).
       
   145 	const TInt c = CeilDiv(n, u);
       
   146 	
       
   147 	// ahead 7: allocate result buffer A
       
   148 	// (Each Ai has SHA1_HASH bytes.)
       
   149 	HBufC8* A_ = HBufC8::NewLC(c * SHA1_HASH);
       
   150 	TPtr8 A = A_->Des();
       
   151 	
       
   152 	// 6. For i=1, 2, ..., c, do the following
       
   153 	
       
   154 	// pre-allocate SHA1 object, DI, and B buffers
       
   155 	CSHA1* sha1 = CSHA1::NewL();
       
   156 	CleanupStack::PushL(sha1);
       
   157 	
       
   158 	const TInt DI_LEN = D_LEN + I_LEN;
       
   159 	HBufC8* DI_ = HBufC8::NewLC(DI_LEN);
       
   160 	TPtr8 DI = DI_->Des();
       
   161 	
       
   162 	const TInt B_LEN = v / 8;
       
   163 	HBufC8* B_ = HBufC8::NewMaxLC(B_LEN);
       
   164 	TPtr8 B = B_->Des();
       
   165 	
       
   166 	for (TInt i = 1; i <= c; ++i)
       
   167 		{
       
   168 		// 6a) Set Ai = H^r(D||I).  (i.e. the rth hash of D||I,
       
   169 		// H(H(H(...H(D||I))))
       
   170 		DI.Copy(D);
       
   171 		DI.Append(I);
       
   172 		
       
   173 		sha1->Reset();
       
   174 		TBuf8<SHA1_HASH> Ai(sha1->Final(DI));
       
   175 		
       
   176 		for (TInt iterCount = 2; iterCount <= r; ++iterCount)
       
   177 			{
       
   178 			Ai.Copy(sha1->Final(Ai));
       
   179 			}
       
   180 		
       
   181 		// 6b) Concatenate copies of Ai to create a string B of length
       
   182 		// v bits (the final copy of Ai may be truncated to create B).
       
   183 		B.Repeat(Ai);
       
   184 		
       
   185 		// 6c) Treating I as a concatenation I0, I1, ..., Ik-1 of
       
   186 		// v-bit blocks, where k=ceil(s/v)+ceil(p/v), modify I by
       
   187 		// setting Ij=(Ij+B+1) mod 2^v for each j.
       
   188 
       
   189 		const TInt k = S_OVER_V_CEIL + P_OVER_V_CEIL;
       
   190 		for (TInt j = 0; j < k; ++j)
       
   191 			{
       
   192 			TPtr8 section = I.MidTPtr((v/8) * j, v/8);
       
   193 			Process6cL(section, B, v);
       
   194 			}
       
   195 		
       
   196 		// 7. Concatenate A1, A2, ..., Ac together to form a pseudo-random
       
   197 		// bit string, A.
       
   198 		A.Append(Ai);
       
   199 		
       
   200 		// stop building A if already have enough bits for key
       
   201 		if (A.Length() >= n / 8)
       
   202 			break;
       
   203 		}
       
   204 
       
   205 	// Use the first n bits of A as the output of this entire process.
       
   206 	aKey.Copy(A.Left(n / 8));
       
   207 	
       
   208 	CleanupStack::PopAndDestroy(8, D_);	// B_, DI_, sha1, A_, I_, P_, S_, D_
       
   209 	}
       
   210 
       
   211 void PKCS12KDF::Process6cL(TDes8& Ij, const TDesC8& B, TInt v)
       
   212 /**
       
   213 	Helper function for DeriveKeyL modifies part of I,
       
   214 	as described in step 6c of SB.2.
       
   215 	
       
   216 	@param	Ij		Section of I (S || P).
       
   217 	@param	B		rth hash of D || I.
       
   218 	@param	v		Number of bits to preserve in result.
       
   219  */
       
   220 	{
       
   221 	// 6c) Treating I as a concatenation I0, I1, ..., Ik-1 of
       
   222 	// v-bit blocks, where k=ceil(s/v)+ceil(p/v), modify I by
       
   223 	// setting Ij=(Ij+B+1) mod 2^v for each j.
       
   224 	
       
   225 	RInteger RI_Ij = RInteger::NewL(Ij);
       
   226 	TCleanupItem ciIj = RI_Ij;
       
   227 	CleanupStack::PushL(ciIj);
       
   228 	
       
   229 	RInteger RI_B = RInteger::NewL(B);
       
   230 	TCleanupItem ciB = RI_B;
       
   231 	CleanupStack::PushL(ciB);
       
   232 	
       
   233 	// these additions can leave
       
   234 	RI_Ij += RI_B;
       
   235 	RI_Ij += 1;
       
   236 	
       
   237 	HBufC8* result = RI_Ij.BufferLC();
       
   238 	
       
   239 	Ij.Zero();
       
   240 	TInt resultLen = result->Length();
       
   241 	
       
   242 	TInt bytesToPreserve = v / 8;
       
   243 	TInt leadingZeroes = bytesToPreserve - resultLen;
       
   244 	if (leadingZeroes <= 0)
       
   245 		Ij.Copy(result->Right(bytesToPreserve));
       
   246 	else
       
   247 		{
       
   248 		Ij.FillZ(leadingZeroes);
       
   249 		Ij.Append(*result);
       
   250 		}
       
   251 	
       
   252 	CleanupStack::PopAndDestroy(3, &RI_Ij);	// result, ciB, ciIj
       
   253 	}
       
   254 
       
   255 #ifdef _DEBUG
       
   256 
       
   257 void PKCS12KDF::Panic(PKCS12KDF::TPanic aPanic)
       
   258 /**
       
   259 	This function is used in debug builds to halt
       
   260 	the current thread when a logic error is detected.
       
   261 	
       
   262 	The current thread is panicked with category "PKCS12KDF"
       
   263 	and the supplied reason.
       
   264 	
       
   265 	@param	aPanic			Converted to numeric value and
       
   266 							used for the panic reason.
       
   267  */
       
   268 	{
       
   269 	_LIT(KPanicCat, "PKCS12KDF");
       
   270 	User::Panic(KPanicCat, aPanic);
       
   271 	}
       
   272 
       
   273 #endif
       
   274