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 +