Back to index

lightning-sunbird  0.9+nobinonly
nsStreamCipher.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Initial Developer of the Original Code is Google Inc.
00015  * Portions created by the Initial Developer are Copyright (C) 2006
00016  * the Initial Developer. All Rights Reserved.
00017  *
00018  * Contributor(s):
00019  *   Tony Chang <tc@google.com>
00020  *
00021  * Alternatively, the contents of this file may be used under the terms of
00022  * either the GNU General Public License Version 2 or later (the "GPL"), or
00023  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00024  * in which case the provisions of the GPL or the LGPL are applicable instead
00025  * of those above. If you wish to allow use of your version of this file only
00026  * under the terms of either the GPL or the LGPL, and not to allow others to
00027  * use your version of this file under the terms of the MPL, indicate your
00028  * decision by deleting the provisions above and replace them with the notice
00029  * and other provisions required by the GPL or the LGPL. If you do not delete
00030  * the provisions above, a recipient may use your version of this file under
00031  * the terms of any one of the MPL, the GPL or the LGPL.
00032  *
00033  * ***** END LICENSE BLOCK ***** */
00034 
00035 #include "nsIKeyModule.h"
00036 #include "nsStreamCipher.h"
00037 #include "nsStreamUtils.h"
00038 #include "base64.h"
00039 
00040 NS_IMPL_ISUPPORTS1(nsStreamCipher, nsIStreamCipher)
00041 
00042 nsStreamCipher::nsStreamCipher()
00043   : mContext(NULL)
00044 {
00045 }
00046 
00047 nsStreamCipher::~nsStreamCipher()
00048 {
00049   if (mContext)
00050     PK11_DestroyContext(mContext, PR_TRUE /* free sub-objects */);
00051 }
00052 
00053 nsresult
00054 nsStreamCipher::InitWithIV_(nsIKeyObject *aKey, SECItem* aIV)
00055 {
00056   NS_ENSURE_ARG_POINTER(aKey);
00057 
00058   // Make sure we have a SYM_KEY.
00059   PRInt16 keyType;
00060   nsresult rv = aKey->GetType(&keyType);
00061   NS_ENSURE_SUCCESS(rv, rv);
00062   if (keyType != nsIKeyObject::SYM_KEY)
00063     return NS_ERROR_INVALID_ARG;
00064 
00065   if (mContext)
00066     PK11_DestroyContext(mContext, PR_TRUE /* free sub-objects */);
00067 
00068   // Get the PK11SymKey out of the key object and create the PK11Context.
00069   void* keyObj;
00070   rv = aKey->GetKeyObj(&keyObj);
00071   NS_ENSURE_SUCCESS(rv, rv);
00072 
00073   PK11SymKey *symkey = NS_REINTERPRET_CAST(PK11SymKey*, keyObj);
00074   if (!symkey)
00075     return NS_ERROR_FAILURE;
00076 
00077   CK_MECHANISM_TYPE cipherMech = PK11_GetMechanism(symkey);
00078 
00079   SECItem *param = nsnull;
00080   // aIV may be null
00081   param = PK11_ParamFromIV(cipherMech, aIV);
00082   if (!param)
00083     return NS_ERROR_FAILURE;
00084 
00085   mContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
00086                                         symkey, param);
00087 
00088   SECITEM_FreeItem(param, PR_TRUE);
00089 
00090   // Something went wrong if mContext doesn't exist.
00091   if (!mContext)
00092     return NS_ERROR_FAILURE;
00093 
00094   // Everything went ok.      
00095   mValue.Truncate();
00096   return NS_OK;
00097 }
00098 
00100 // nsIStreamCipher
00101 
00102 NS_IMETHODIMP nsStreamCipher::Init(nsIKeyObject *aKey)
00103 {
00104   return InitWithIV_(aKey, nsnull);
00105 }
00106 
00107 NS_IMETHODIMP nsStreamCipher::InitWithIV(nsIKeyObject *aKey,
00108                                          const PRUint8 *aIV, PRUint32 aIVLen)
00109 {
00110   SECItem IV;
00111   IV.data = (unsigned char*)aIV;
00112   IV.len = aIVLen;
00113   return InitWithIV_(aKey, &IV);
00114 }
00115 
00116 NS_IMETHODIMP nsStreamCipher::Update(const PRUint8 *aData, PRUint32 aLen)
00117 {
00118   if (!mContext)
00119     return NS_ERROR_NOT_INITIALIZED;
00120 
00121   unsigned char* output = new unsigned char[aLen];
00122   if (!output)
00123     return NS_ERROR_OUT_OF_MEMORY;
00124   unsigned char* input = (unsigned char*)aData;
00125   
00126   PRInt32 setLen;
00127   SECStatus rv = PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen);
00128   NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
00129   NS_ASSERTION((PRUint32)setLen == aLen, "data length should not change");
00130 
00131   mValue.Append((const char*)output, aLen);
00132 
00133   delete [] output;
00134 
00135   return NS_OK;
00136 }
00137 
00138 NS_IMETHODIMP nsStreamCipher::UpdateFromStream(nsIInputStream *aStream,
00139                                                PRInt32 aLen)
00140 {
00141   if (!mContext)
00142     return NS_ERROR_NOT_INITIALIZED;
00143 
00144   nsCString inputString;
00145   nsresult rv = NS_ConsumeStream(aStream, aLen, inputString);
00146   NS_ENSURE_SUCCESS(rv, rv);
00147   
00148   return UpdateFromString(inputString);
00149 }
00150 
00151 NS_IMETHODIMP nsStreamCipher::UpdateFromString(const nsACString& aInput)
00152 {
00153   if (!mContext)
00154     return NS_ERROR_NOT_INITIALIZED;
00155 
00156   const nsCString& flatInput = PromiseFlatCString(aInput);
00157   unsigned char* input = (unsigned char*)flatInput.get();
00158   PRUint32 len = aInput.Length();
00159 
00160   unsigned char* output = new unsigned char[len];
00161   if (!output)
00162     return NS_ERROR_OUT_OF_MEMORY;
00163 
00164   PRInt32 setLen;
00165   SECStatus rv = PK11_CipherOp(mContext, output, &setLen, len, input, len);
00166   NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
00167   NS_ASSERTION((PRUint32)setLen == len, "data length should not change");
00168 
00169   mValue.Append((const char*)output, len);
00170   delete [] output;
00171 
00172   return NS_OK;
00173 }
00174 
00175 NS_IMETHODIMP nsStreamCipher::Finish(PRBool aASCII, nsACString & _retval)
00176 {
00177   if (!mContext)
00178     return NS_ERROR_NOT_INITIALIZED;
00179 
00180   if (aASCII) {
00181     char *asciiData = BTOA_DataToAscii((unsigned char*)(mValue.get()),
00182                                        mValue.Length());
00183     _retval.Assign(asciiData);
00184     PORT_Free(asciiData);
00185   } else {
00186     _retval.Assign(mValue);
00187   }
00188 
00189   return NS_OK;
00190 }
00191 
00192 NS_IMETHODIMP nsStreamCipher::Discard(PRInt32 aLen)
00193 {
00194   if (!mContext)
00195     return NS_ERROR_NOT_INITIALIZED;
00196 
00197   unsigned char* output = new unsigned char[aLen];
00198   if (!output)
00199     return NS_ERROR_OUT_OF_MEMORY;
00200 
00201   unsigned char* input = new unsigned char[aLen];
00202   if (!input) {
00203     delete [] output;
00204     return NS_ERROR_OUT_OF_MEMORY;
00205   }
00206 
00207   PRInt32 setLen;
00208   SECStatus rv = PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen);
00209   NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
00210   NS_ASSERTION(setLen == aLen, "data length should not change");
00211   
00212   delete [] output;
00213   delete [] input;
00214   return NS_OK;
00215 }