michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsIKeyModule.h" michael@0: #include "nsStreamCipher.h" michael@0: #include "nsStreamUtils.h" michael@0: #include "base64.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(nsStreamCipher, nsIStreamCipher) michael@0: michael@0: nsStreamCipher::nsStreamCipher() michael@0: : mContext(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsStreamCipher::~nsStreamCipher() michael@0: { michael@0: if (mContext) michael@0: PK11_DestroyContext(mContext, true /* free sub-objects */); michael@0: } michael@0: michael@0: nsresult michael@0: nsStreamCipher::InitWithIV_(nsIKeyObject *aKey, SECItem* aIV) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aKey); michael@0: michael@0: // Make sure we have a SYM_KEY. michael@0: int16_t keyType; michael@0: nsresult rv = aKey->GetType(&keyType); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (keyType != nsIKeyObject::SYM_KEY) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (mContext) michael@0: PK11_DestroyContext(mContext, true /* free sub-objects */); michael@0: michael@0: // Get the PK11SymKey out of the key object and create the PK11Context. michael@0: void* keyObj; michael@0: rv = aKey->GetKeyObj(&keyObj); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: PK11SymKey *symkey = reinterpret_cast(keyObj); michael@0: if (!symkey) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: CK_MECHANISM_TYPE cipherMech = PK11_GetMechanism(symkey); michael@0: michael@0: SECItem *param = nullptr; michael@0: // aIV may be null michael@0: param = PK11_ParamFromIV(cipherMech, aIV); michael@0: if (!param) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: mContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, michael@0: symkey, param); michael@0: michael@0: SECITEM_FreeItem(param, true); michael@0: michael@0: // Something went wrong if mContext doesn't exist. michael@0: if (!mContext) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // Everything went ok. michael@0: mValue.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////////////////// michael@0: // nsIStreamCipher michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::Init(nsIKeyObject *aKey) michael@0: { michael@0: return InitWithIV_(aKey, nullptr); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::InitWithIV(nsIKeyObject *aKey, michael@0: const uint8_t *aIV, uint32_t aIVLen) michael@0: { michael@0: SECItem IV; michael@0: IV.data = (unsigned char*)aIV; michael@0: IV.len = aIVLen; michael@0: return InitWithIV_(aKey, &IV); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::Update(const uint8_t *aData, uint32_t aLen) michael@0: { michael@0: if (!mContext) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: unsigned char* output = new unsigned char[aLen]; michael@0: unsigned char* input = (unsigned char*)aData; michael@0: michael@0: int32_t setLen; michael@0: michael@0: #ifdef DEBUG michael@0: SECStatus rv = michael@0: #endif michael@0: PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen); michael@0: NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); michael@0: NS_ASSERTION((uint32_t)setLen == aLen, "data length should not change"); michael@0: michael@0: mValue.Append((const char*)output, aLen); michael@0: michael@0: delete [] output; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::UpdateFromStream(nsIInputStream *aStream, michael@0: int32_t aLen) michael@0: { michael@0: if (!mContext) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: nsCString inputString; michael@0: nsresult rv = NS_ConsumeStream(aStream, aLen, inputString); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return UpdateFromString(inputString); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::UpdateFromString(const nsACString& aInput) michael@0: { michael@0: if (!mContext) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: const nsCString& flatInput = PromiseFlatCString(aInput); michael@0: unsigned char* input = (unsigned char*)flatInput.get(); michael@0: uint32_t len = aInput.Length(); michael@0: michael@0: unsigned char* output = new unsigned char[len]; michael@0: michael@0: int32_t setLen; michael@0: michael@0: #ifdef DEBUG michael@0: SECStatus rv = michael@0: #endif michael@0: PK11_CipherOp(mContext, output, &setLen, len, input, len); michael@0: NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); michael@0: NS_ASSERTION((uint32_t)setLen == len, "data length should not change"); michael@0: michael@0: mValue.Append((const char*)output, len); michael@0: delete [] output; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::Finish(bool aASCII, nsACString & _retval) michael@0: { michael@0: if (!mContext) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: if (aASCII) { michael@0: char *asciiData = BTOA_DataToAscii((unsigned char*)(mValue.get()), michael@0: mValue.Length()); michael@0: _retval.Assign(asciiData); michael@0: PORT_Free(asciiData); michael@0: } else { michael@0: _retval.Assign(mValue); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsStreamCipher::Discard(int32_t aLen) michael@0: { michael@0: if (!mContext) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: unsigned char* output = new unsigned char[aLen]; michael@0: unsigned char* input = new unsigned char[aLen]; michael@0: michael@0: int32_t setLen; michael@0: michael@0: #ifdef DEBUG michael@0: SECStatus rv = michael@0: #endif michael@0: PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen); michael@0: NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); michael@0: NS_ASSERTION(setLen == aLen, "data length should not change"); michael@0: michael@0: delete [] output; michael@0: delete [] input; michael@0: return NS_OK; michael@0: }