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