os/security/crypto/weakcryptospi/source/padding/padding.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	TRAPD(err, GenerateRandomBytesL(rnd));
   299 	if((err != KErrNone) && (err != KErrNotSecure))
   300 	    User::Leave(err);
   301 
   302 	TInt i = 2;
   303 	TInt j = 0;
   304 	for (; i<(startOfData-1);)
   305 		{
   306 		if (rnd[j])
   307 			{
   308 			aOutput[i++]=rnd[j];
   309 			}
   310 		if (++j==256)
   311 			{
   312 			TRAP(err, GenerateRandomBytesL(rnd));
   313 			if((err != KErrNone) && (err != KErrNotSecure))
   314 				User::Leave(err);
   315 			j=0;
   316 			}
   317 		}
   318 
   319 	j=0;
   320 	aOutput[startOfData-1]=0;				// separator
   321 	for (i=startOfData;i<BlockSize();i++,j++)
   322 		{
   323 		aOutput[i]=aInput[j];
   324 		}
   325 	}
   326 	
   327 void CPaddingPKCS1Encryption::UnPadL(const TDesC8& aInput,TDes8& aOutput)
   328 	{
   329 	TInt inputLen = aInput.Length();
   330 	if (inputLen <= 0)				
   331 		User::Leave(KErrInvalidPadding);	//	Invalid padding data
   332 
   333 	// Leading zero may have been stripped off by integer class
   334 	TInt dataStart=0;
   335 	if (aInput[dataStart] == 0)
   336 		{
   337 		++dataStart;
   338 		}
   339 	
   340 	// expecting mode 2 padding, otherwise broken
   341 	if (dataStart == inputLen || aInput[dataStart] != 2)	
   342 		{
   343 		User::Leave(KErrInvalidPadding);
   344 		}
   345 	++dataStart;
   346 
   347 	// skip random non zero bytes
   348 	while (dataStart < inputLen && aInput[dataStart])
   349 		{
   350 		++dataStart;
   351 		}
   352 
   353 	// expecting zero separator
   354 	if (dataStart == inputLen || aInput[dataStart] != 0)
   355 		{
   356 		User::Leave(KErrInvalidPadding);		
   357 		}
   358 	++dataStart;
   359 
   360 	TInt len = inputLen - dataStart;
   361 	__ASSERT_DEBUG(aOutput.MaxLength() >= len, User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
   362 
   363 	aOutput.SetLength(len);
   364 	TInt i=0;
   365 	while (dataStart<inputLen)
   366 		{
   367 		aOutput[i++]=aInput[dataStart++];
   368 		}
   369 	}
   370 
   371 TInt CPaddingPKCS1Encryption::MinPaddingLength(void) const
   372 	{
   373 	return 11; //0x00, 0x02, <min of 8 random octets>, 0x00
   374 	}