1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is mozilla.org code.
15 : *
16 : * The Initial Developer of the Original Code is Google Inc.
17 : * Portions created by the Initial Developer are Copyright (C) 2006
18 : * the Initial Developer. All Rights Reserved.
19 : *
20 : * Contributor(s):
21 : * Tony Chang <tc@google.com>
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsIKeyModule.h"
38 : #include "nsStreamCipher.h"
39 : #include "nsStreamUtils.h"
40 : #include "base64.h"
41 :
42 0 : NS_IMPL_ISUPPORTS1(nsStreamCipher, nsIStreamCipher)
43 :
44 0 : nsStreamCipher::nsStreamCipher()
45 0 : : mContext(NULL)
46 : {
47 0 : }
48 :
49 0 : nsStreamCipher::~nsStreamCipher()
50 : {
51 0 : if (mContext)
52 0 : PK11_DestroyContext(mContext, true /* free sub-objects */);
53 0 : }
54 :
55 : nsresult
56 0 : nsStreamCipher::InitWithIV_(nsIKeyObject *aKey, SECItem* aIV)
57 : {
58 0 : NS_ENSURE_ARG_POINTER(aKey);
59 :
60 : // Make sure we have a SYM_KEY.
61 : PRInt16 keyType;
62 0 : nsresult rv = aKey->GetType(&keyType);
63 0 : NS_ENSURE_SUCCESS(rv, rv);
64 0 : if (keyType != nsIKeyObject::SYM_KEY)
65 0 : return NS_ERROR_INVALID_ARG;
66 :
67 0 : if (mContext)
68 0 : PK11_DestroyContext(mContext, true /* free sub-objects */);
69 :
70 : // Get the PK11SymKey out of the key object and create the PK11Context.
71 : void* keyObj;
72 0 : rv = aKey->GetKeyObj(&keyObj);
73 0 : NS_ENSURE_SUCCESS(rv, rv);
74 :
75 0 : PK11SymKey *symkey = reinterpret_cast<PK11SymKey*>(keyObj);
76 0 : if (!symkey)
77 0 : return NS_ERROR_FAILURE;
78 :
79 0 : CK_MECHANISM_TYPE cipherMech = PK11_GetMechanism(symkey);
80 :
81 0 : SECItem *param = nsnull;
82 : // aIV may be null
83 0 : param = PK11_ParamFromIV(cipherMech, aIV);
84 0 : if (!param)
85 0 : return NS_ERROR_FAILURE;
86 :
87 : mContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT,
88 0 : symkey, param);
89 :
90 0 : SECITEM_FreeItem(param, true);
91 :
92 : // Something went wrong if mContext doesn't exist.
93 0 : if (!mContext)
94 0 : return NS_ERROR_FAILURE;
95 :
96 : // Everything went ok.
97 0 : mValue.Truncate();
98 0 : return NS_OK;
99 : }
100 :
101 : /////////////////////////////////////////////////////////////////////////////
102 : // nsIStreamCipher
103 :
104 0 : NS_IMETHODIMP nsStreamCipher::Init(nsIKeyObject *aKey)
105 : {
106 0 : return InitWithIV_(aKey, nsnull);
107 : }
108 :
109 0 : NS_IMETHODIMP nsStreamCipher::InitWithIV(nsIKeyObject *aKey,
110 : const PRUint8 *aIV, PRUint32 aIVLen)
111 : {
112 : SECItem IV;
113 0 : IV.data = (unsigned char*)aIV;
114 0 : IV.len = aIVLen;
115 0 : return InitWithIV_(aKey, &IV);
116 : }
117 :
118 0 : NS_IMETHODIMP nsStreamCipher::Update(const PRUint8 *aData, PRUint32 aLen)
119 : {
120 0 : if (!mContext)
121 0 : return NS_ERROR_NOT_INITIALIZED;
122 :
123 0 : unsigned char* output = new unsigned char[aLen];
124 0 : if (!output)
125 0 : return NS_ERROR_OUT_OF_MEMORY;
126 0 : unsigned char* input = (unsigned char*)aData;
127 :
128 : PRInt32 setLen;
129 :
130 : #ifdef DEBUG
131 : SECStatus rv =
132 : #endif
133 0 : PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen);
134 0 : NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
135 0 : NS_ASSERTION((PRUint32)setLen == aLen, "data length should not change");
136 :
137 0 : mValue.Append((const char*)output, aLen);
138 :
139 0 : delete [] output;
140 :
141 0 : return NS_OK;
142 : }
143 :
144 0 : NS_IMETHODIMP nsStreamCipher::UpdateFromStream(nsIInputStream *aStream,
145 : PRInt32 aLen)
146 : {
147 0 : if (!mContext)
148 0 : return NS_ERROR_NOT_INITIALIZED;
149 :
150 0 : nsCString inputString;
151 0 : nsresult rv = NS_ConsumeStream(aStream, aLen, inputString);
152 0 : NS_ENSURE_SUCCESS(rv, rv);
153 :
154 0 : return UpdateFromString(inputString);
155 : }
156 :
157 0 : NS_IMETHODIMP nsStreamCipher::UpdateFromString(const nsACString& aInput)
158 : {
159 0 : if (!mContext)
160 0 : return NS_ERROR_NOT_INITIALIZED;
161 :
162 0 : const nsCString& flatInput = PromiseFlatCString(aInput);
163 0 : unsigned char* input = (unsigned char*)flatInput.get();
164 0 : PRUint32 len = aInput.Length();
165 :
166 0 : unsigned char* output = new unsigned char[len];
167 0 : if (!output)
168 0 : return NS_ERROR_OUT_OF_MEMORY;
169 :
170 : PRInt32 setLen;
171 :
172 : #ifdef DEBUG
173 : SECStatus rv =
174 : #endif
175 0 : PK11_CipherOp(mContext, output, &setLen, len, input, len);
176 0 : NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
177 0 : NS_ASSERTION((PRUint32)setLen == len, "data length should not change");
178 :
179 0 : mValue.Append((const char*)output, len);
180 0 : delete [] output;
181 :
182 0 : return NS_OK;
183 : }
184 :
185 0 : NS_IMETHODIMP nsStreamCipher::Finish(bool aASCII, nsACString & _retval)
186 : {
187 0 : if (!mContext)
188 0 : return NS_ERROR_NOT_INITIALIZED;
189 :
190 0 : if (aASCII) {
191 0 : char *asciiData = BTOA_DataToAscii((unsigned char*)(mValue.get()),
192 0 : mValue.Length());
193 0 : _retval.Assign(asciiData);
194 0 : PORT_Free(asciiData);
195 : } else {
196 0 : _retval.Assign(mValue);
197 : }
198 :
199 0 : return NS_OK;
200 : }
201 :
202 0 : NS_IMETHODIMP nsStreamCipher::Discard(PRInt32 aLen)
203 : {
204 0 : if (!mContext)
205 0 : return NS_ERROR_NOT_INITIALIZED;
206 :
207 0 : unsigned char* output = new unsigned char[aLen];
208 0 : if (!output)
209 0 : return NS_ERROR_OUT_OF_MEMORY;
210 :
211 0 : unsigned char* input = new unsigned char[aLen];
212 0 : if (!input) {
213 0 : delete [] output;
214 0 : return NS_ERROR_OUT_OF_MEMORY;
215 : }
216 :
217 : PRInt32 setLen;
218 :
219 : #ifdef DEBUG
220 : SECStatus rv =
221 : #endif
222 0 : PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen);
223 0 : NS_ASSERTION(rv == SECSuccess, "failed to encrypt");
224 0 : NS_ASSERTION(setLen == aLen, "data length should not change");
225 :
226 0 : delete [] output;
227 0 : delete [] input;
228 0 : return NS_OK;
229 : }
|