crypto/weakcrypto/source/padding/padding.cpp
changeset 71 dd83586b62d6
equal deleted inserted replaced
66:8873e6835f7b 71:dd83586b62d6
       
     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