javaextensions/satsa/crypto/src/stssymmetriccipher.cpp
branchRCL_3
changeset 14 04becd199f91
equal deleted inserted replaced
13:f5050f1da672 14:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2008 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 "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:  Implementation of STSSymmetricCipher
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include "stssymmetriccipher.h"
       
    21 #include <openssl/rand.h>
       
    22 #include <msymmetriccipher.h>
       
    23 #include <bufferedtransformation.h>
       
    24 #include <cbcmode.h>
       
    25 #include <padding.h>
       
    26 #include <random.h>
       
    27 #include "javajniutils.h"
       
    28 #include "stsconstants.h"
       
    29 #include "logger.h"
       
    30 
       
    31 namespace java
       
    32 {
       
    33 namespace satsa
       
    34 {
       
    35 
       
    36 
       
    37 STSSymmetricCipher::STSSymmetricCipher()
       
    38 {
       
    39     mCipher = NULL;
       
    40     mCipherCtx = NULL;
       
    41     mCipherType = NULL;
       
    42 
       
    43 }
       
    44 
       
    45 
       
    46 STSSymmetricCipher::~STSSymmetricCipher()
       
    47 {
       
    48     // cleanup the cipher context
       
    49     if (mCipherCtx != NULL)
       
    50     {
       
    51         EVP_CIPHER_CTX_cleanup(mCipherCtx);
       
    52         mCipherCtx = NULL;
       
    53     }
       
    54     else
       
    55     {
       
    56         // do nothing
       
    57     }
       
    58 }
       
    59 
       
    60 STSSymmetricCipher* STSSymmetricCipher::Create(
       
    61     STSTransformation* aTransformation, int* errCode)
       
    62 {
       
    63     LOG(ESATSA, EInfo, "STSSymmetricCipher::Create+");
       
    64     STSSymmetricCipher* self = new STSSymmetricCipher;
       
    65     if (self == NULL)
       
    66     {
       
    67         *errCode = KSTSErrNoMemory;
       
    68         return NULL;
       
    69     }
       
    70     int retVal = self->Construct(aTransformation);
       
    71     if (0 == retVal)
       
    72     {
       
    73         *errCode = retVal;
       
    74         return self;
       
    75     }
       
    76     else
       
    77     {
       
    78         ELOG(ESATSA, "STSSymmetricCipher::Create failed");
       
    79         *errCode = retVal;
       
    80         delete self;
       
    81         self = 0;
       
    82         return NULL;
       
    83     }
       
    84 
       
    85 }
       
    86 
       
    87 int STSSymmetricCipher::Construct(STSTransformation* aTransformation)
       
    88 {
       
    89     LOG(ESATSA, EInfo, "STSSymmetricCipher::Construct+");
       
    90     // load ciphers that are needed for lookup by openc apis
       
    91     OpenSSL_add_all_ciphers();
       
    92 
       
    93     // Check transformation validity.
       
    94 
       
    95     // Check mode
       
    96     if (aTransformation->Mode() != STSModeCBC && aTransformation->Mode()
       
    97             != STSModeECB && aTransformation->Mode() != STSModeNONE)
       
    98     {
       
    99         ELOG(ESATSA, "STSSymmetricCipher::Construct: mode is not supported");
       
   100         // Mode is not supported
       
   101         return (KSTSErrNoSuchAlgorithm);
       
   102 
       
   103     }
       
   104 
       
   105     // Check padding
       
   106     if (aTransformation->Padding() != STSPaddingNone
       
   107             && aTransformation->Padding() != STSPaddingPKCS7
       
   108             && aTransformation->Padding() != STSPaddingPKCS5)
       
   109     {
       
   110         ELOG(ESATSA, "Construct: padding not supported");
       
   111         // Padding is not supported
       
   112         return (KSTSErrNoSuchPadding);
       
   113 
       
   114     }
       
   115 
       
   116     // No errors, object constructed successfully
       
   117     LOG(ESATSA, EInfo, "STSSymmetricCipher::Construct--");
       
   118     return 0;
       
   119 
       
   120 }
       
   121 
       
   122 jint STSSymmetricCipher::DoInit(JNIEnv* aJni, const TCipherMode aMode,
       
   123                                 const jstring aKeyAlgorithm, const jstring aKeyFormat,
       
   124                                 const jbyteArray aKeyEncoded, const jbyteArray aParams)
       
   125 {
       
   126     LOG(ESATSA, EInfo, "STSSymmetricCipher::DoInit+");
       
   127     //Function return value
       
   128     jint retVal = 0;
       
   129 
       
   130     // clear the old iv as the cipher is now being initialized/re-initialized
       
   131     if (mIV != NULL)
       
   132     {
       
   133         delete mIV;
       
   134         mIV = NULL;
       
   135     }
       
   136     miv_length = 0;
       
   137 
       
   138     //clear the old mKey
       
   139     if (mKey != NULL)
       
   140     {
       
   141         delete mKey;
       
   142         mKey = NULL;
       
   143     }
       
   144     mKey_length = 0;
       
   145 
       
   146     // Format: Only raw keys are supported
       
   147     std::wstring key_format;
       
   148     try
       
   149     {
       
   150         key_format = java::util::JniUtils::jstringToWstring(aJni, aKeyFormat);
       
   151     }
       
   152     catch (...)
       
   153     {
       
   154         ELOG(ESATSA, "DoInit: caught exception. Return error code");
       
   155         return (KSTSErrInvalidKey);
       
   156     }
       
   157     if (key_format != STSKeyFormatRAW)
       
   158     {
       
   159         ELOG(ESATSA, "DoInit:Not raw keys");
       
   160         return (KSTSErrInvalidKey);
       
   161     }
       
   162 
       
   163     // Key must be created for used algorithm
       
   164     std::wstring key_algorithm;
       
   165     try
       
   166     {
       
   167         key_algorithm = java::util::JniUtils::jstringToWstring(aJni,
       
   168                         aKeyAlgorithm);
       
   169     }
       
   170     catch (...)
       
   171     {
       
   172         ELOG(ESATSA, "DoInit: caught exception. Return error code");
       
   173         return (KSTSErrInvalidKey);
       
   174     }
       
   175     if (mTransformation->Algorithm() != key_algorithm)
       
   176     {
       
   177         ELOG(ESATSA, "DoInit:Not proper algorithm");
       
   178         return (KSTSErrInvalidKey);
       
   179     }
       
   180 
       
   181     // read the Key
       
   182     //Create the native array from jbytearray
       
   183     mKey_length = aJni->GetArrayLength(aKeyEncoded);
       
   184     mKey = new unsigned char[mKey_length];
       
   185     aJni->GetByteArrayRegion(aKeyEncoded, 0, mKey_length, (signed char*) mKey);
       
   186 
       
   187     // Set the cipher type and Mode
       
   188     if (mTransformation->Algorithm() == STSAlgorithmDES)
       
   189     {
       
   190         ELOG(ESATSA, "DoInit: DES algorithm");
       
   191         if (mTransformation->Mode() == STSModeCBC)
       
   192         {
       
   193             mCipherType = EVP_des_cbc();
       
   194         }
       
   195         else if (mTransformation->Mode() == STSModeECB)
       
   196         {
       
   197             mCipherType = EVP_des_ecb();
       
   198         }
       
   199         else if (mTransformation->Mode() == STSModeNONE)
       
   200         {
       
   201             mCipherType = EVP_des_cbc();
       
   202         }
       
   203 
       
   204     }
       
   205     else if (mTransformation->Algorithm() == STSAlgorithm3DES)
       
   206     {
       
   207         LOG(ESATSA, EInfo, "STSSymmetricCipher::DoInit: 3DES algorithm");
       
   208         if (mTransformation->Mode() == STSModeCBC)
       
   209         {
       
   210             mCipherType = EVP_des_ede3_cbc();
       
   211         }
       
   212         else if (mTransformation->Mode() == STSModeECB)
       
   213         {
       
   214             mCipherType = EVP_des_ede3_ecb();
       
   215         }
       
   216         else if (mTransformation->Mode() == STSModeNONE)
       
   217         {
       
   218             mCipherType = EVP_des_ede3_cbc();
       
   219         }
       
   220 
       
   221     }
       
   222     else if (mTransformation->Algorithm() == STSAlgorithmRC2)
       
   223     {
       
   224         LOG(ESATSA, EInfo, "STSSymmetricCipher::DoInit: RC2 algorothm");
       
   225         if (mTransformation->Mode() == STSModeCBC)
       
   226         {
       
   227             mCipherType = EVP_rc2_cbc();
       
   228         }
       
   229         else if (mTransformation->Mode() == STSModeECB)
       
   230         {
       
   231             mCipherType = EVP_rc2_ecb();
       
   232         }
       
   233         else if (mTransformation->Mode() == STSModeNONE)
       
   234         {
       
   235             mCipherType = EVP_rc2_cbc();
       
   236         }
       
   237 
       
   238     }
       
   239     else if (mTransformation->Algorithm() == STSAlgorithmAES)
       
   240     {
       
   241         LOG(ESATSA, EInfo, "STSSymmetricCipher::DoInit: AES algorithm");
       
   242         // AES algorithms based on key size
       
   243         switch (mKey_length)
       
   244         {
       
   245         case 16:
       
   246             if (mTransformation->Mode() == STSModeCBC)
       
   247             {
       
   248                 mCipherType = EVP_aes_128_cbc();
       
   249             }
       
   250             else if (mTransformation->Mode() == STSModeECB)
       
   251             {
       
   252                 mCipherType = EVP_aes_128_ecb();
       
   253             }
       
   254             else if (mTransformation->Mode() == STSModeNONE)
       
   255             {
       
   256                 mCipherType = EVP_aes_128_cbc();
       
   257             }
       
   258             break;
       
   259         case 24:
       
   260             if (mTransformation->Mode() == STSModeCBC)
       
   261             {
       
   262                 mCipherType = EVP_aes_192_cbc();
       
   263             }
       
   264             else if (mTransformation->Mode() == STSModeECB)
       
   265             {
       
   266                 mCipherType = EVP_aes_192_ecb();
       
   267             }
       
   268             else if (mTransformation->Mode() == STSModeNONE)
       
   269             {
       
   270                 mCipherType = EVP_aes_192_cbc();
       
   271             }
       
   272             break;
       
   273         case 32:
       
   274             if (mTransformation->Mode() == STSModeCBC)
       
   275             {
       
   276                 mCipherType = EVP_aes_256_cbc();
       
   277             }
       
   278             else if (mTransformation->Mode() == STSModeECB)
       
   279             {
       
   280                 mCipherType = EVP_aes_256_ecb();
       
   281             }
       
   282             else if (mTransformation->Mode() == STSModeNONE)
       
   283             {
       
   284                 mCipherType = EVP_aes_256_cbc();
       
   285             }
       
   286             break;
       
   287         default:
       
   288             // Invalid Key Size
       
   289             ELOG(ESATSA, "DoInit:Invalid Key Size");
       
   290             return (KSTSErrInvalidKey);
       
   291 
       
   292         };
       
   293     }
       
   294 
       
   295     // cipher type could not be determined
       
   296     if (mCipherType == NULL)
       
   297     {
       
   298         ELOG(ESATSA, "DoInit:cipher type could not be determined");
       
   299         return (KSTSErrNoSuchAlgorithm);
       
   300     }
       
   301     // determined cipher type,  determine and validate the parameters
       
   302     // Block size is needed for padding and iv
       
   303     int blocksize = EVP_CIPHER_block_size(mCipherType);
       
   304 
       
   305     // Check parameters, create IV for algorithm.
       
   306     if (mTransformation->Mode() == STSModeECB)
       
   307     {
       
   308         // ECB mode may not have IV
       
   309         if (aParams)
       
   310         {
       
   311             ELOG(ESATSA, "DoInit:ECB mode may not have IV");
       
   312             return (KSTSErrArgument);
       
   313         }
       
   314     }
       
   315     else
       
   316     {
       
   317         // CBC mode must have IV
       
   318         if (aParams)
       
   319         {
       
   320             // IV was given as a parameter
       
   321             // Create the native array from jbytearray
       
   322             miv_length = aJni->GetArrayLength(aParams);
       
   323             mIV = new unsigned char[miv_length];
       
   324             aJni->GetByteArrayRegion(aParams, 0, miv_length, (signed char*) mIV);
       
   325 
       
   326             // IV's size must be same as block size.
       
   327             if (blocksize != miv_length)
       
   328             {
       
   329                 ELOG(ESATSA, "DoInit:blocksize mismatch");
       
   330                 return (KSTSErrArgument);
       
   331             }
       
   332 
       
   333         }
       
   334         else
       
   335         {
       
   336             if (aMode == EDecryptMode)
       
   337             {
       
   338                 ELOG(ESATSA, "DoInit: In decrypt mode IV is needed.");
       
   339                 // In encrypt mode IV is needed.
       
   340                 return (KSTSErrArgument);
       
   341             }
       
   342 
       
   343             // IV was not given, generate new random iv same as blocksize
       
   344             miv_length = blocksize;
       
   345             mIV = new unsigned char[miv_length];
       
   346             if (mIV)
       
   347             {
       
   348                 RAND_pseudo_bytes(mIV, miv_length);
       
   349             }
       
   350             else
       
   351             {
       
   352                 mIV = NULL;
       
   353                 miv_length = 0;
       
   354                 ELOG(ESATSA, "DoInit:IV is not proper");
       
   355                 return KSTSErrNoMemory;
       
   356             }
       
   357 
       
   358         }
       
   359 
       
   360     }
       
   361 
       
   362     // Initialize the cipher context
       
   363     mCipherCtx = new EVP_CIPHER_CTX;
       
   364     if (mCipherCtx == NULL)
       
   365     {
       
   366         ELOG(ESATSA, "DoInit:cipher context is null");
       
   367         // cipher context could not be allocated
       
   368         return (KSTSErrNoMemory);
       
   369     }
       
   370     // Initialize the cipher context
       
   371     EVP_CIPHER_CTX_init(mCipherCtx);
       
   372 
       
   373     // Create decryptor or encryptor according to mode
       
   374     mMode = aMode;
       
   375     int ret;
       
   376     if (mMode == EEncryptMode)
       
   377     {
       
   378         ret = EVP_CipherInit_ex(mCipherCtx, mCipherType, NULL, mKey, mIV, 1);
       
   379         if (0 == ret)
       
   380         {
       
   381             ELOG(ESATSA, "DoInit:cipher:encrypt:cipher could not be initialized");
       
   382             retVal = KSTSErrNoMemory;
       
   383         }
       
   384     }
       
   385     else
       
   386     {
       
   387         // Otherwise EDecryptMode
       
   388         ret = EVP_CipherInit_ex(mCipherCtx, mCipherType, NULL, mKey, mIV, 0);
       
   389         if (0 == ret)
       
   390         {
       
   391             ELOG(ESATSA, "DoInit:cipher:decrypt:cipher could not be initialized");
       
   392             retVal = KSTSErrNoMemory;
       
   393         }
       
   394     }
       
   395 
       
   396     // Set the padding
       
   397     if (mTransformation->Padding() == STSPaddingPKCS7
       
   398             || mTransformation->Padding() == STSPaddingPKCS5)
       
   399     {
       
   400         LOG(ESATSA, EInfo, "Padding for pkcs7 or pkcs5");
       
   401         EVP_CIPHER_CTX_set_padding(mCipherCtx, 1); // always returns 1 (Success)
       
   402     }
       
   403     else
       
   404     {
       
   405         EVP_CIPHER_CTX_set_padding(mCipherCtx, 0); // always returns 1 (Success)
       
   406     }
       
   407 
       
   408     // reset state.
       
   409     mBytesProcessed = 0;
       
   410     //return
       
   411     LOG(ESATSA, EInfo, "STSSymmetricCipher::DoInit--");
       
   412     return retVal;
       
   413 }
       
   414 
       
   415 jint STSSymmetricCipher::DoFinal(JNIEnv* aJni, jbyteArray aInput,
       
   416                                  jint aInputOffset, jint aInputLength, jbyteArray aOutput,
       
   417                                  jint aOutputOffset)
       
   418 {
       
   419     LOG(ESATSA, EInfo, "STSSymmetricCipher::DoFinal+");
       
   420     // Variable to hold the error code
       
   421     int retVal = 0;
       
   422 
       
   423     if (mCipherCtx == NULL || mCipherType == NULL)
       
   424     {
       
   425         ELOG(ESATSA, "Cipher context/type not ready");
       
   426         // Init was not called successfully.
       
   427         return (KSTSErrIllegalState);
       
   428     }
       
   429 
       
   430     int blocksize = EVP_CIPHER_block_size(mCipherType);
       
   431     int bytesProcessed = aInputLength + mBytesProcessed;
       
   432     // reset state.
       
   433     mBytesProcessed = 0;
       
   434     if ((bytesProcessed % blocksize != 0) && ((mMode == EDecryptMode)
       
   435             || (mTransformation->Padding() == STSPaddingNone)))
       
   436     {
       
   437         ELOG(ESATSA, "Processing failed");
       
   438         return (KSTSErrIllegalBlockSize);
       
   439     }
       
   440 
       
   441     // read the input data
       
   442     unsigned char* inputBuf = new unsigned char[aInputLength];
       
   443     aJni->GetByteArrayRegion(aInput, aInputOffset, aInputLength,
       
   444                              (signed char *) inputBuf);
       
   445 
       
   446     // create the output native array to hold the output
       
   447     int max_output_length = aInputLength + blocksize - 1;
       
   448     unsigned char* outputBuf = new unsigned char[max_output_length];
       
   449     int outputLength = 0;
       
   450 
       
   451     // if inputlength is  > 0 then there is some input data to update
       
   452     if (aInputLength > 0)
       
   453     {
       
   454         // call update
       
   455         retVal = EVP_CipherUpdate(mCipherCtx, outputBuf, &outputLength,
       
   456                                   inputBuf, aInputLength);
       
   457         if (0 == retVal)
       
   458         {
       
   459             ELOG(ESATSA, "Update OpenC API failed");
       
   460             // openc api returned failure
       
   461             return KSTSErrBadPadding;
       
   462         }
       
   463     }
       
   464 
       
   465     // finalize the output
       
   466     int final_length = 0;
       
   467     retVal = EVP_CipherFinal_ex(mCipherCtx, outputBuf + outputLength,
       
   468                                 &final_length);
       
   469     if (0 == retVal)
       
   470     {
       
   471         ELOG(ESATSA, "Final OpenC API failed");
       
   472         // openc api returned failure
       
   473         return KSTSErrBadPadding;
       
   474     }
       
   475 
       
   476     // Re-initialize the cipher back to its init state
       
   477     int ret = EVP_CIPHER_CTX_cleanup(mCipherCtx);
       
   478     if (0 == ret)
       
   479     {
       
   480         ELOG(ESATSA, "Cleanup OpenC API failed");
       
   481         retVal = KSTSErrIllegalState;
       
   482     }
       
   483     // Initialize the cipher context
       
   484     EVP_CIPHER_CTX_init(mCipherCtx);
       
   485 
       
   486     // Create decryptor or encryptor according to mode
       
   487     if (mMode == EEncryptMode)
       
   488     {
       
   489         int ret = EVP_CipherInit_ex(mCipherCtx, mCipherType, NULL, mKey, mIV, 1);
       
   490         if (0 == ret)
       
   491         {
       
   492             ELOG(ESATSA, "encrypt mode:cipher init failed");
       
   493             retVal = KSTSErrNoMemory;
       
   494         }
       
   495     }
       
   496     else
       
   497     {
       
   498         // Otherwise EDecryptMode
       
   499         int ret = EVP_CipherInit_ex(mCipherCtx, mCipherType, NULL, mKey, mIV, 0);
       
   500         if (0 == ret)
       
   501         {
       
   502             retVal = KSTSErrNoMemory;
       
   503         }
       
   504     }
       
   505 
       
   506     // Set the padding
       
   507     if (mTransformation->Padding() == STSPaddingPKCS7
       
   508             || mTransformation->Padding() == STSPaddingPKCS5)
       
   509     {
       
   510         EVP_CIPHER_CTX_set_padding(mCipherCtx, 1); // always returns 1(Success)
       
   511     }
       
   512     else
       
   513     {
       
   514         EVP_CIPHER_CTX_set_padding(mCipherCtx, 0); // always returns 1(Success)
       
   515     }
       
   516 
       
   517     if ((outputLength + final_length) > (aJni->GetArrayLength(aOutput)
       
   518                                          - aOutputOffset))
       
   519     {
       
   520         // Output buffer cannot hold the output of the cipher
       
   521         return (KSTSErrShortBuffer);
       
   522     }
       
   523 
       
   524     aJni->SetByteArrayRegion(aOutput, aOutputOffset, (outputLength
       
   525                              + final_length), (signed char *) outputBuf);
       
   526     retVal = outputLength + final_length;
       
   527 
       
   528     LOG(ESATSA, EInfo, "STSSymmetricCipher::DoFinal--");
       
   529     return retVal;
       
   530 
       
   531 }
       
   532 
       
   533 jint STSSymmetricCipher::Update(JNIEnv* aJni, jbyteArray aInput,
       
   534                                 jint aInputOffset, jint aInputLength, jbyteArray aOutput,
       
   535                                 jint aOutputOffset)
       
   536 {
       
   537     LOG(ESATSA, EInfo, "STSSymmetricCipher::Update+");
       
   538     // Variable to hold the error code
       
   539     int retVal = 0;
       
   540 
       
   541     if (mCipherCtx == NULL || mCipherType == NULL)
       
   542     {
       
   543         ELOG(ESATSA, "Init was not called successfully");
       
   544         // Init was not called successfully.
       
   545         return (KSTSErrIllegalState);
       
   546     }
       
   547     else if (0 == aInputLength)
       
   548     {
       
   549         // if inputlength is 0 then there is nothing to update
       
   550         ELOG(ESATSA, "Inputlength 0, nothing to update");
       
   551         // return 0
       
   552         return retVal;
       
   553     }
       
   554 
       
   555     // read the input data
       
   556     unsigned char* inputBuf = new unsigned char[aInputLength];
       
   557     aJni->GetByteArrayRegion(aInput, aInputOffset, aInputLength,
       
   558                              (signed char *) inputBuf);
       
   559 
       
   560     // create the output native array to hold the output
       
   561     int blocksize = EVP_CIPHER_block_size(mCipherType);
       
   562     int max_output_length = aInputLength + blocksize - 1;
       
   563     unsigned char* outputBuf = new unsigned char[max_output_length];
       
   564     int outputLength = 0;
       
   565 
       
   566     // call the update function
       
   567     retVal = EVP_CipherUpdate(mCipherCtx, outputBuf, &outputLength, inputBuf,
       
   568                               aInputLength);
       
   569     if (0 == retVal)
       
   570     {
       
   571         ELOG(ESATSA, "Update OpenC API failed");
       
   572         // openc api returned failure
       
   573         return KSTSErrBadPadding;
       
   574     }
       
   575     else if ((outputLength) > (aJni->GetArrayLength(aOutput) - aOutputOffset))
       
   576     {
       
   577         ELOG(ESATSA, "Update: Short buffer");
       
   578         return (KSTSErrShortBuffer);
       
   579     }
       
   580 
       
   581     aJni->SetByteArrayRegion(aOutput, aOutputOffset, outputLength,
       
   582                              (signed char *) outputBuf);
       
   583 
       
   584     mBytesProcessed += aInputLength;
       
   585 
       
   586     // return the number of bytes processed.
       
   587     retVal = outputLength;
       
   588     LOG(ESATSA, EInfo, "STSSymmetricCipher::Update--");
       
   589     return retVal;
       
   590 
       
   591 }
       
   592 } // namespace satsa
       
   593 } // namespace java
       
   594 
       
   595