crypto/weakcryptospi/source/padding/padding.cpp
changeset 19 cd501b96611d
child 41 9b5a3a9fddf8
equal deleted inserted replaced
15:da2ae96f639b 19:cd501b96611d
       
     1 /*
       
     2 * Copyright (c) 1999-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 <e32base.h>
       
    20 #include <random.h>
       
    21 #include <padding.h>
       
    22 #include <securityerr.h>
       
    23 #include <cryptopanic.h>
       
    24 
       
    25 #include "paddingshim.h"
       
    26 
       
    27 /* CPadding */
       
    28 CPadding::CPadding(void) : iBlockBytes(-1)
       
    29 	{
       
    30 	}
       
    31 
       
    32 EXPORT_C CPadding::CPadding(TInt aBlockBytes) : iBlockBytes(aBlockBytes)
       
    33 	{
       
    34 	__ASSERT_ALWAYS(aBlockBytes > 0, User::Invariant());
       
    35 	}
       
    36 
       
    37 EXPORT_C void CPadding::SetBlockSize(TInt aBlockBytes)
       
    38 	{
       
    39 	__ASSERT_ALWAYS(aBlockBytes > 0, User::Invariant());
       
    40 	iBlockBytes = aBlockBytes;
       
    41 	}
       
    42 
       
    43 EXPORT_C TInt CPadding::BlockSize(void) const
       
    44 	{
       
    45 	return iBlockBytes;
       
    46 	}
       
    47 
       
    48 EXPORT_C TInt CPadding::MaxPaddedLength(TInt /*aInputBytes*/) const
       
    49 	{
       
    50 	return BlockSize();
       
    51 	}
       
    52 
       
    53 EXPORT_C TInt CPadding::MaxUnPaddedLength(TInt aInputBytes) const
       
    54 	{
       
    55 	return aInputBytes - MinPaddingLength();
       
    56 	}
       
    57 
       
    58 EXPORT_C void CPadding::PadL(const TDesC8& aInput, TDes8& aOutput)
       
    59 	{
       
    60 	// Check that the input is small enough to fit inside one padded block
       
    61 	// Won't leave if input text is equal to blocksize. Let DoPadL handle such situations
       
    62 	if(aInput.Length() > BlockSize() - MinPaddingLength()
       
    63 			&& aInput.Length() != BlockSize()) 	
       
    64 		User::Leave(KErrArgument);
       
    65 	
       
    66 	// Check that the output descriptor supplied is large enough to store the result
       
    67 	if(aOutput.MaxLength() < MaxPaddedLength(aInput.Length())) 	
       
    68 		User::Leave(KErrOverflow);
       
    69 
       
    70 	// Call the virtual function, implemented by derived classes
       
    71 	DoPadL(aInput, aOutput);
       
    72 	}
       
    73 
       
    74 TInt CPadding::GetExtension(TUint aExtensionId, TAny*& a0, TAny* a1)
       
    75 	{
       
    76 	return Extension_(aExtensionId, a0, a1);
       
    77 	}
       
    78 
       
    79 /* CPaddingNone */
       
    80 EXPORT_C CPaddingNone* CPaddingNone::NewL(TInt aBlockBytes)
       
    81 	{
       
    82 	__ASSERT_ALWAYS(aBlockBytes > 0, User::Leave(KErrArgument));
       
    83 	return CPaddingNoneShim::NewL(aBlockBytes);
       
    84 	}
       
    85 
       
    86 EXPORT_C CPaddingNone* CPaddingNone::NewLC(TInt aBlockBytes)
       
    87 	{
       
    88 	CPaddingNone* self = CPaddingNone::NewL(aBlockBytes);
       
    89 	CleanupStack::PushL(self);
       
    90 	return self;
       
    91 	}
       
    92 
       
    93 EXPORT_C CPaddingNone::CPaddingNone(TInt aBlockBytes):CPadding(aBlockBytes)
       
    94 	{
       
    95 	}
       
    96 
       
    97 void CPaddingNone::DoPadL(const TDesC8& aInput,TDes8& aOutput)
       
    98 	{
       
    99 	aOutput.Append(aInput);
       
   100 	}
       
   101 
       
   102 void CPaddingNone::UnPadL(const TDesC8& aInput,TDes8& aOutput)
       
   103 	{
       
   104 	__ASSERT_DEBUG(aOutput.MaxLength() >= MaxPaddedLength(aInput.Length()), User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
       
   105 	aOutput.Append(aInput);
       
   106 	}
       
   107 
       
   108 TInt CPaddingNone::MinPaddingLength(void) const
       
   109 	{
       
   110 	return 0;
       
   111 	}
       
   112 
       
   113 TInt CPaddingNone::MaxPaddedLength(TInt aInputSize) const
       
   114 	{
       
   115 	return aInputSize;
       
   116 	}
       
   117 
       
   118 /* CPaddingSSLv3 */
       
   119 EXPORT_C CPaddingSSLv3* CPaddingSSLv3::NewL(TInt aBlockBytes)
       
   120 	{
       
   121 	__ASSERT_ALWAYS(aBlockBytes > 0, User::Leave(KErrArgument));
       
   122 	return CPaddingSSLv3Shim::NewL(aBlockBytes);	
       
   123 	}
       
   124 
       
   125 EXPORT_C CPaddingSSLv3* CPaddingSSLv3::NewLC(TInt aBlockBytes)
       
   126 	{
       
   127 	CPaddingSSLv3* self = CPaddingSSLv3::NewL(aBlockBytes);
       
   128 	CleanupStack::PushL(self);
       
   129 	return self;
       
   130 	}
       
   131 
       
   132 EXPORT_C CPaddingSSLv3::CPaddingSSLv3(TInt aBlockBytes):CPadding(aBlockBytes)
       
   133 	{
       
   134 	}
       
   135 
       
   136 void CPaddingSSLv3::DoPadL(const TDesC8& aInput,TDes8& aOutput)
       
   137 	{
       
   138 	TInt paddingBytes=BlockSize()-(aInput.Length()%BlockSize());
       
   139 	aOutput.Append(aInput);
       
   140 	aOutput.SetLength(aOutput.Length()+paddingBytes);
       
   141 	for (TInt i=1;i<=paddingBytes;i++)
       
   142 		{
       
   143 		aOutput[aOutput.Length()-i]=(TUint8)(paddingBytes-1);
       
   144 		}
       
   145 	}
       
   146 
       
   147 void CPaddingSSLv3::UnPadL(const TDesC8& aInput,TDes8& aOutput)
       
   148 	{
       
   149 	TInt paddingLen = aInput[aInput.Length()-1] + 1;
       
   150 
       
   151 	if (paddingLen > aInput.Length())
       
   152 		{
       
   153 		User::Leave(KErrInvalidPadding);
       
   154 		}
       
   155 
       
   156 	TInt outlen = aInput.Length() - paddingLen;
       
   157 
       
   158 	__ASSERT_DEBUG(aOutput.MaxLength() >= outlen, User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
       
   159 
       
   160 	aOutput.Append(aInput.Left(outlen));
       
   161 	}
       
   162 
       
   163 TInt CPaddingSSLv3::MinPaddingLength(void) const
       
   164 	{
       
   165 	//if aInputBytes is 1 less than the blocksize then we get 1 byte of padding
       
   166 	return 1;
       
   167 	}
       
   168 
       
   169 TInt CPaddingSSLv3::MaxPaddedLength(TInt aInputBytes) const
       
   170 	{
       
   171 	TUint padBytes = BlockSize() - (aInputBytes % BlockSize());
       
   172 	return padBytes + aInputBytes;
       
   173 	}
       
   174 
       
   175 /* CPaddingPKCS1Signature */
       
   176 EXPORT_C CPaddingPKCS1Signature* CPaddingPKCS1Signature::NewL(TInt aBlockBytes)
       
   177 	{
       
   178 	return CPaddingPKCS1SignatureShim::NewL(aBlockBytes);
       
   179 	}
       
   180 
       
   181 EXPORT_C CPaddingPKCS1Signature* CPaddingPKCS1Signature::NewLC(TInt aBlockBytes)
       
   182 	{
       
   183 	CPaddingPKCS1Signature* self = CPaddingPKCS1Signature::NewL(aBlockBytes);
       
   184 	CleanupStack::PushL(self);
       
   185 	return self;
       
   186 	}
       
   187 
       
   188 EXPORT_C CPaddingPKCS1Signature::CPaddingPKCS1Signature(TInt aBlockBytes)
       
   189 	: CPadding(aBlockBytes)
       
   190 	{
       
   191 	}
       
   192 
       
   193 void CPaddingPKCS1Signature::DoPadL(const TDesC8& aInput,TDes8& aOutput)
       
   194 	{
       
   195 	aOutput.SetLength(BlockSize());
       
   196 	TInt i;
       
   197 	TInt j;
       
   198 	aOutput[0]=0;
       
   199 	TInt startOfData=BlockSize()-aInput.Length();
       
   200 	// PKCS1 also specifies a block type 0 for private key operations but
       
   201 	// does not recommend its use. This block type (0) is compatible with 
       
   202 	// unpadded data though so you can create PKCS1 type 0 blocks using 
       
   203 	// CPaddingNone.
       
   204 	aOutput[1]=1;				// Block type 1 (private key operation)
       
   205 	for (i=2;i<(startOfData-1);i++)
       
   206 		{
       
   207 		aOutput[i]=0xff;
       
   208 		}
       
   209 	j=0;
       
   210 	aOutput[startOfData-1]=0;				// separator
       
   211 	for (i=startOfData;i<BlockSize();i++,j++)
       
   212 		{
       
   213 		aOutput[i]=aInput[j];
       
   214 		}
       
   215 	}
       
   216 	
       
   217 void CPaddingPKCS1Signature::UnPadL(const TDesC8& aInput,TDes8& aOutput)
       
   218 	{
       
   219 	// erm, oops, this is not quite as simplistic as it first looks...
       
   220 	// our integer class will strip any leading zeros so we might actually
       
   221 	// get some real data that starts out looking like padding but isn't 
       
   222 	// really
       
   223 	
       
   224 	TInt inputLen = aInput.Length();
       
   225 	if (inputLen <=0 )				
       
   226 		User::Leave(KErrInvalidPadding);	//	Invalid padding data
       
   227 
       
   228 	// Leading zero may have been stripped off by integer class
       
   229 	TInt dataStart=0;
       
   230 	if (aInput[dataStart] == 0)
       
   231 		{
       
   232 		++dataStart;
       
   233 		}
       
   234 
       
   235 	if (dataStart < inputLen && aInput[dataStart])		//	might be mode one or mode zero,
       
   236 		{
       
   237 		++dataStart;
       
   238 		while (dataStart < inputLen && aInput[dataStart] == 0xff)
       
   239 			{
       
   240 			++dataStart;
       
   241 			}
       
   242 		
       
   243 		if (dataStart == inputLen || aInput[dataStart])	//	this would mean theres no zero between 0x01ff and data...so its not mode one
       
   244 			dataStart=0;			//	mode zero, start from begining of data
       
   245 		else
       
   246 			++dataStart;
       
   247 		}
       
   248 	else							//	We've definitely got a mode zero 
       
   249 		{							//	or broken data, assume mode zero
       
   250 		dataStart=0;		
       
   251 		}
       
   252 
       
   253 	TInt len=inputLen-dataStart;
       
   254 
       
   255 	__ASSERT_DEBUG(aOutput.MaxLength() >= len, User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
       
   256 
       
   257 	aOutput.SetLength(len);
       
   258 	TInt i=0;
       
   259 	while (dataStart<inputLen)
       
   260 		{
       
   261 		aOutput[i++]=aInput[dataStart++];
       
   262 		}
       
   263 	}
       
   264 
       
   265 TInt CPaddingPKCS1Signature::MinPaddingLength(void) const
       
   266 	{
       
   267 	return 11; //0x00, 0x01, <MIN of 8 0xFF octets> , 0x00
       
   268 	}
       
   269 
       
   270 /* CPaddingPKCS1Encryption */
       
   271 EXPORT_C CPaddingPKCS1Encryption* CPaddingPKCS1Encryption::NewL(
       
   272 	TInt aBlockBytes)
       
   273 	{
       
   274 	return CPaddingPKCS1EncryptionShim::NewL(aBlockBytes);
       
   275 	}
       
   276 
       
   277 EXPORT_C CPaddingPKCS1Encryption* CPaddingPKCS1Encryption::NewLC(
       
   278 	TInt aBlockBytes)
       
   279 	{
       
   280 	CPaddingPKCS1Encryption* self = CPaddingPKCS1Encryption::NewL(aBlockBytes);
       
   281 	CleanupStack::PushL(self);
       
   282 	return self;
       
   283 	}
       
   284 
       
   285 EXPORT_C CPaddingPKCS1Encryption::CPaddingPKCS1Encryption(TInt aBlockBytes)
       
   286 	: CPadding(aBlockBytes)
       
   287 	{
       
   288 	}
       
   289 
       
   290 void CPaddingPKCS1Encryption::DoPadL(const TDesC8& aInput,TDes8& aOutput)
       
   291 	{
       
   292 	aOutput.SetLength(BlockSize());
       
   293 	
       
   294 	aOutput[0]=0;
       
   295 	TInt startOfData=BlockSize()-aInput.Length();
       
   296 	aOutput[1]=2;				// Block type 2 (public key operation)
       
   297 	TBuf8<256> rnd(256);
       
   298 	GenerateRandomBytesL(rnd);
       
   299 
       
   300 	TInt i = 2;
       
   301 	TInt j = 0;
       
   302 	for (; i<(startOfData-1);)
       
   303 		{
       
   304 		if (rnd[j])
       
   305 			{
       
   306 			aOutput[i++]=rnd[j];
       
   307 			}
       
   308 		if (++j==256)
       
   309 			{
       
   310 			GenerateRandomBytesL(rnd);
       
   311 			j=0;
       
   312 			}
       
   313 		}
       
   314 
       
   315 	j=0;
       
   316 	aOutput[startOfData-1]=0;				// separator
       
   317 	for (i=startOfData;i<BlockSize();i++,j++)
       
   318 		{
       
   319 		aOutput[i]=aInput[j];
       
   320 		}
       
   321 	}
       
   322 	
       
   323 void CPaddingPKCS1Encryption::UnPadL(const TDesC8& aInput,TDes8& aOutput)
       
   324 	{
       
   325 	TInt inputLen = aInput.Length();
       
   326 	if (inputLen <= 0)				
       
   327 		User::Leave(KErrInvalidPadding);	//	Invalid padding data
       
   328 
       
   329 	// Leading zero may have been stripped off by integer class
       
   330 	TInt dataStart=0;
       
   331 	if (aInput[dataStart] == 0)
       
   332 		{
       
   333 		++dataStart;
       
   334 		}
       
   335 	
       
   336 	// expecting mode 2 padding, otherwise broken
       
   337 	if (dataStart == inputLen || aInput[dataStart] != 2)	
       
   338 		{
       
   339 		User::Leave(KErrInvalidPadding);
       
   340 		}
       
   341 	++dataStart;
       
   342 
       
   343 	// skip random non zero bytes
       
   344 	while (dataStart < inputLen && aInput[dataStart])
       
   345 		{
       
   346 		++dataStart;
       
   347 		}
       
   348 
       
   349 	// expecting zero separator
       
   350 	if (dataStart == inputLen || aInput[dataStart] != 0)
       
   351 		{
       
   352 		User::Leave(KErrInvalidPadding);		
       
   353 		}
       
   354 	++dataStart;
       
   355 
       
   356 	TInt len = inputLen - dataStart;
       
   357 	__ASSERT_DEBUG(aOutput.MaxLength() >= len, User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
       
   358 
       
   359 	aOutput.SetLength(len);
       
   360 	TInt i=0;
       
   361 	while (dataStart<inputLen)
       
   362 		{
       
   363 		aOutput[i++]=aInput[dataStart++];
       
   364 		}
       
   365 	}
       
   366 
       
   367 TInt CPaddingPKCS1Encryption::MinPaddingLength(void) const
       
   368 	{
       
   369 	return 11; //0x00, 0x02, <min of 8 random octets>, 0x00
       
   370 	}