sl@0: /* sl@0: * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "desimpl.h" sl@0: sl@0: #include "destables.h" sl@0: #include "common/inlines.h" sl@0: #include "des.inl" sl@0: #include "pluginconfig.h" sl@0: #include "symmetriccipherimpl.h" sl@0: #include sl@0: sl@0: sl@0: // bit 0 is left-most in byte sl@0: static const TInt bytebit[] = {0200,0100,040,020,010,04,02,01}; sl@0: sl@0: using namespace SoftwareCrypto; sl@0: sl@0: /* CDesImpl */ sl@0: CDesImpl::CDesImpl( sl@0: TUint8 aBlockBytes, sl@0: TUid aCryptoMode, sl@0: TUid aOperationMode, sl@0: TUid aPadding) : sl@0: CSymmetricBlockCipherImpl(aBlockBytes, aCryptoMode, aOperationMode, aPadding) sl@0: { sl@0: } sl@0: sl@0: CDesImpl* CDesImpl::NewL(const CKey& aKey, TUid aCryptoMode, TUid aOperationMode, TUid aPadding) sl@0: { sl@0: CDesImpl* self = CDesImpl::NewLC(aKey, aCryptoMode, aOperationMode, aPadding); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CDesImpl* CDesImpl::NewLC(const CKey& aKey, TUid aCryptoMode, TUid aOperationMode, TUid aPadding) sl@0: { sl@0: CDesImpl* self = new(ELeave) CDesImpl(KDesBlockBytes, aCryptoMode, aOperationMode, aPadding); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aKey); sl@0: sl@0: const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid); sl@0: TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyContent.Size()) - keyContent.Size()); sl@0: return self; sl@0: } sl@0: sl@0: CDesImpl::~CDesImpl() sl@0: { sl@0: // make sure key information isn't visible to other processes if the sl@0: // page is reused. sl@0: Mem::FillZ(&iK, sizeof(iK)); sl@0: } sl@0: sl@0: void CDesImpl::ConstructL(const CKey& aKey) sl@0: { sl@0: CSymmetricBlockCipherImpl::ConstructL(aKey); sl@0: SetKeySchedule(); sl@0: } sl@0: sl@0: CExtendedCharacteristics* CDesImpl::CreateExtendedCharacteristicsL() sl@0: { sl@0: // All Symbian software plug-ins have unlimited concurrency, cannot be reserved sl@0: // for exclusive use and are not CERTIFIED to be standards compliant. sl@0: return CExtendedCharacteristics::NewL(KMaxTInt, EFalse); sl@0: } sl@0: sl@0: const CExtendedCharacteristics* CDesImpl::GetExtendedCharacteristicsL() sl@0: { sl@0: return CDesImpl::CreateExtendedCharacteristicsL(); sl@0: } sl@0: sl@0: TUid CDesImpl::ImplementationUid() const sl@0: { sl@0: return KCryptoPluginDesUid; sl@0: } sl@0: sl@0: TBool CDesImpl::IsValidKeyLength(TInt aKeyBytes) const sl@0: { sl@0: return (aKeyBytes == KDesKeyBytes); sl@0: } sl@0: sl@0: TInt CDesImpl::GetKeyStrength() const sl@0: { sl@0: // parity bits are excluded sl@0: return BytesToBits(KDesKeyBytes - 8); sl@0: } sl@0: sl@0: void CDesImpl::TransformEncrypt( sl@0: TUint8* aBuffer, sl@0: TUint aNumBlocks) sl@0: { sl@0: for (TInt i = 0; i < aNumBlocks; ++i) sl@0: { sl@0: ModeEncryptStart(aBuffer); sl@0: TUint32 l, r; sl@0: // Split the block into 2 word-sized big endian portions sl@0: GetBlockBigEndian(aBuffer, l, r); sl@0: IPerm(l,r); sl@0: DoTransform(l, r, iK); sl@0: FPerm(l,r); sl@0: sl@0: // Put the portions back into the block as little endian sl@0: PutBlockBigEndian(aBuffer, r, l); sl@0: sl@0: ModeEncryptEnd(aBuffer); sl@0: aBuffer += KDesBlockBytes; sl@0: } sl@0: } sl@0: sl@0: void CDesImpl::TransformDecrypt( sl@0: TUint8* aBuffer, sl@0: TUint aNumBlocks) sl@0: { sl@0: for (TInt i = 0; i < aNumBlocks; ++i) sl@0: { sl@0: ModeDecryptStart(aBuffer); sl@0: sl@0: TUint32 l, r; sl@0: // Split the block into 2 word-sized big endian portions sl@0: GetBlockBigEndian(aBuffer, l, r); sl@0: sl@0: IPerm(l,r); sl@0: DoTransform(l, r, iK); sl@0: FPerm(l,r); sl@0: sl@0: // Put the portions back into the block as little endian sl@0: PutBlockBigEndian(aBuffer, r, l); sl@0: sl@0: ModeDecryptEnd(aBuffer); sl@0: aBuffer += KDesBlockBytes; sl@0: } sl@0: } sl@0: sl@0: void CDesImpl::SetKeySchedule() sl@0: { sl@0: if (iCryptoMode.iUid == KCryptoModeEncrypt) sl@0: { sl@0: SetEncryptKeySchedule(*iKey, iK); sl@0: } sl@0: else sl@0: { sl@0: ASSERT(iCryptoMode.iUid == KCryptoModeDecrypt); sl@0: SetDecryptKeySchedule(*iKey, iK); sl@0: } sl@0: } sl@0: sl@0: void CDesImpl::DoTransform(TUint32& l, TUint32& r, const TUint32* aKeySchedule) sl@0: { sl@0: TInt i = 0; sl@0: for (; i<8; i++) sl@0: { sl@0: TUint32 work = rotrFixed(r, 4U) ^ aKeySchedule[4*i+0]; sl@0: l ^= DES_TABLE::sbox[6][(work) & 0x3f] sl@0: ^ DES_TABLE::sbox[4][(work >> 8) & 0x3f] sl@0: ^ DES_TABLE::sbox[2][(work >> 16) & 0x3f] sl@0: ^ DES_TABLE::sbox[0][(work >> 24) & 0x3f]; sl@0: work = r ^ aKeySchedule[4*i+1]; sl@0: l ^= DES_TABLE::sbox[7][(work) & 0x3f] sl@0: ^ DES_TABLE::sbox[5][(work >> 8) & 0x3f] sl@0: ^ DES_TABLE::sbox[3][(work >> 16) & 0x3f] sl@0: ^ DES_TABLE::sbox[1][(work >> 24) & 0x3f]; sl@0: sl@0: work = rotrFixed(l, 4U) ^ aKeySchedule[4*i+2]; sl@0: r ^= DES_TABLE::sbox[6][(work) & 0x3f] sl@0: ^ DES_TABLE::sbox[4][(work >> 8) & 0x3f] sl@0: ^ DES_TABLE::sbox[2][(work >> 16) & 0x3f] sl@0: ^ DES_TABLE::sbox[0][(work >> 24) & 0x3f]; sl@0: work = l ^ aKeySchedule[4*i+3]; sl@0: r ^= DES_TABLE::sbox[7][(work) & 0x3f] sl@0: ^ DES_TABLE::sbox[5][(work >> 8) & 0x3f] sl@0: ^ DES_TABLE::sbox[3][(work >> 16) & 0x3f] sl@0: ^ DES_TABLE::sbox[1][(work >> 24) & 0x3f]; sl@0: } sl@0: } sl@0: sl@0: void CDesImpl::SetEncryptKeySchedule(const TDesC8& aKey, TUint32* aKeySchedule) sl@0: { sl@0: TInt i=0, j=0, l=0, m=0; sl@0: sl@0: // Form a byte array from aKey, taking endianess into account (little->big) sl@0: TUint8 key[8]; // For big endian byte array sl@0: Mem::Copy(&key, &aKey[0], 8); sl@0: sl@0: TUint8 buffer[56+56+8]; sl@0: TUint8* const pc1m = &buffer[0]; /* place to modify pc1 into */ sl@0: TUint8* const pcr = pc1m + 56; /* place to rotate pc1 into */ sl@0: TUint8* const ks = pcr + 56; sl@0: sl@0: for (j=0; j<56; j++) sl@0: {/* convert pc1 to bits of key */ sl@0: l = DES_TABLE::pc1[j]-1; /* integer bit location */ sl@0: m = l & 07; /* find bit */ sl@0: pc1m[j]=(key[l>>3] & /* find which key byte l is in */ sl@0: bytebit[m]) /* and which bit of that byte */ sl@0: ? (TUint8)1 : (TUint8)0; /* and store 1-bit result */ sl@0: } sl@0: sl@0: for (i=0; i<16; i++) sl@0: {/* key chunk for each iteration */ sl@0: Mem::FillZ(ks,8); /* Clear key schedule */ sl@0: for (j=0; j<56; j++) sl@0: /* rotate pc1 the right amount */ sl@0: pcr[j] = pc1m[(l=j+DES_TABLE::totrot[i])<(j<28? 28 : 56) ? l: l-28]; sl@0: sl@0: /* rotate left and right halves independently */ sl@0: sl@0: for (j=0; j<48; j++) sl@0: {/* select bits individually */ sl@0: /* check bit that goes to ks[j] */ sl@0: if (pcr[DES_TABLE::pc2[j]-1]) sl@0: {/* mask it in if it's there */ sl@0: l= j % 6; sl@0: ks[j/6] |= bytebit[l] >> 2; sl@0: } sl@0: } sl@0: sl@0: /* Now convert to odd/even interleaved form for use in F */ sl@0: (*(aKeySchedule+(2*i))) = ((TUint32)ks[0] << 24) sl@0: | ((TUint32)ks[2] << 16) sl@0: | ((TUint32)ks[4] << 8) sl@0: | ((TUint32)ks[6]); sl@0: sl@0: (*(aKeySchedule+(2*i+1))) = ((TUint32)ks[1] << 24) sl@0: | ((TUint32)ks[3] << 16) sl@0: | ((TUint32)ks[5] << 8) sl@0: | ((TUint32)ks[7]); sl@0: } sl@0: } sl@0: sl@0: void CDesImpl::SetDecryptKeySchedule(const TDesC8& aKey, TUint32* aKeySchedule) sl@0: { sl@0: SetEncryptKeySchedule(aKey, aKeySchedule); sl@0: ReverseKeySchedule(aKeySchedule); sl@0: }