Update contrib.
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
21 #include "pkcs12kdf.h"
24 EXPORT_C HBufC8* PKCS12KDF::GeneratePasswordLC(const TDesC& aDes)
26 Convert the supplied string to a byte string, as described
27 in SB.1 of the PKCS 12 v1.0.
29 Each character is converted to a big endian two-byte value,
30 and a terminating NULL character is appended to the end.
32 @param aDes String to use as password.
35 const TInt len = aDes.Length();
36 HBufC8* pwdBytes = HBufC8::NewMaxLC((len + 1) * 2);
37 TPtr8 pbDes = pwdBytes->Des();
43 pbDes[i * 2] = ch >> 8;
44 pbDes[(i * 2) + 1] = ch;
47 pbDes[i * 2] = pbDes[(i * 2) + 1] = 0;
52 static TInt CeilDiv(TInt aNumerator, TInt aDenominator)
54 Utility function returns ceil(aNumerator / aDenominator).
56 @param aNumerator The numerator.
57 @param aDenominator Denominator, which cannot be zero.
58 @return ceil(aNumerator / aDenominator)
61 TInt result = aNumerator / aDenominator;
62 if ((aNumerator % aDenominator) > 0)
67 EXPORT_C void PKCS12KDF::DeriveKeyL(
68 TDes8& aKey, TIDByteType aIDType,
69 const TDesC8& aPasswd, const TDesC8& aSalt, const TUint aIterations)
71 Generate a key for the supplied password and salt.
72 This implementation uses SHA1 as the hashing algorithm.
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.
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.)
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));
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;
109 // (numbered steps are from the standard)
110 // 1. Construct a string, D (the "diversifier"), by concatenating
112 const TInt D_LEN = v / 8;
113 HBufC8* D_ = HBufC8::NewMaxLC(D_LEN);
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,
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);
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
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);
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);
144 // 5. Set c=ceil(n/u).
145 const TInt c = CeilDiv(n, u);
147 // ahead 7: allocate result buffer A
148 // (Each Ai has SHA1_HASH bytes.)
149 HBufC8* A_ = HBufC8::NewLC(c * SHA1_HASH);
152 // 6. For i=1, 2, ..., c, do the following
154 // pre-allocate SHA1 object, DI, and B buffers
155 CSHA1* sha1 = CSHA1::NewL();
156 CleanupStack::PushL(sha1);
158 const TInt DI_LEN = D_LEN + I_LEN;
159 HBufC8* DI_ = HBufC8::NewLC(DI_LEN);
160 TPtr8 DI = DI_->Des();
162 const TInt B_LEN = v / 8;
163 HBufC8* B_ = HBufC8::NewMaxLC(B_LEN);
166 for (TInt i = 1; i <= c; ++i)
168 // 6a) Set Ai = H^r(D||I). (i.e. the rth hash of D||I,
169 // H(H(H(...H(D||I))))
174 TBuf8<SHA1_HASH> Ai(sha1->Final(DI));
176 for (TInt iterCount = 2; iterCount <= r; ++iterCount)
178 Ai.Copy(sha1->Final(Ai));
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).
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.
189 const TInt k = S_OVER_V_CEIL + P_OVER_V_CEIL;
190 for (TInt j = 0; j < k; ++j)
192 TPtr8 section = I.MidTPtr((v/8) * j, v/8);
193 Process6cL(section, B, v);
196 // 7. Concatenate A1, A2, ..., Ac together to form a pseudo-random
200 // stop building A if already have enough bits for key
201 if (A.Length() >= n / 8)
205 // Use the first n bits of A as the output of this entire process.
206 aKey.Copy(A.Left(n / 8));
208 CleanupStack::PopAndDestroy(8, D_); // B_, DI_, sha1, A_, I_, P_, S_, D_
211 void PKCS12KDF::Process6cL(TDes8& Ij, const TDesC8& B, TInt v)
213 Helper function for DeriveKeyL modifies part of I,
214 as described in step 6c of SB.2.
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.
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.
225 RInteger RI_Ij = RInteger::NewL(Ij);
226 TCleanupItem ciIj = RI_Ij;
227 CleanupStack::PushL(ciIj);
229 RInteger RI_B = RInteger::NewL(B);
230 TCleanupItem ciB = RI_B;
231 CleanupStack::PushL(ciB);
233 // these additions can leave
237 HBufC8* result = RI_Ij.BufferLC();
240 TInt resultLen = result->Length();
242 TInt bytesToPreserve = v / 8;
243 TInt leadingZeroes = bytesToPreserve - resultLen;
244 if (leadingZeroes <= 0)
245 Ij.Copy(result->Right(bytesToPreserve));
248 Ij.FillZ(leadingZeroes);
252 CleanupStack::PopAndDestroy(3, &RI_Ij); // result, ciB, ciIj
257 void PKCS12KDF::Panic(PKCS12KDF::TPanic aPanic)
259 This function is used in debug builds to halt
260 the current thread when a logic error is detected.
262 The current thread is panicked with category "PKCS12KDF"
263 and the supplied reason.
265 @param aPanic Converted to numeric value and
266 used for the panic reason.
269 _LIT(KPanicCat, "PKCS12KDF");
270 User::Panic(KPanicCat, aPanic);