|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "nsIKeyModule.h" |
|
6 #include "nsStreamCipher.h" |
|
7 #include "nsStreamUtils.h" |
|
8 #include "base64.h" |
|
9 |
|
10 NS_IMPL_ISUPPORTS(nsStreamCipher, nsIStreamCipher) |
|
11 |
|
12 nsStreamCipher::nsStreamCipher() |
|
13 : mContext(nullptr) |
|
14 { |
|
15 } |
|
16 |
|
17 nsStreamCipher::~nsStreamCipher() |
|
18 { |
|
19 if (mContext) |
|
20 PK11_DestroyContext(mContext, true /* free sub-objects */); |
|
21 } |
|
22 |
|
23 nsresult |
|
24 nsStreamCipher::InitWithIV_(nsIKeyObject *aKey, SECItem* aIV) |
|
25 { |
|
26 NS_ENSURE_ARG_POINTER(aKey); |
|
27 |
|
28 // Make sure we have a SYM_KEY. |
|
29 int16_t keyType; |
|
30 nsresult rv = aKey->GetType(&keyType); |
|
31 NS_ENSURE_SUCCESS(rv, rv); |
|
32 if (keyType != nsIKeyObject::SYM_KEY) |
|
33 return NS_ERROR_INVALID_ARG; |
|
34 |
|
35 if (mContext) |
|
36 PK11_DestroyContext(mContext, true /* free sub-objects */); |
|
37 |
|
38 // Get the PK11SymKey out of the key object and create the PK11Context. |
|
39 void* keyObj; |
|
40 rv = aKey->GetKeyObj(&keyObj); |
|
41 NS_ENSURE_SUCCESS(rv, rv); |
|
42 |
|
43 PK11SymKey *symkey = reinterpret_cast<PK11SymKey*>(keyObj); |
|
44 if (!symkey) |
|
45 return NS_ERROR_FAILURE; |
|
46 |
|
47 CK_MECHANISM_TYPE cipherMech = PK11_GetMechanism(symkey); |
|
48 |
|
49 SECItem *param = nullptr; |
|
50 // aIV may be null |
|
51 param = PK11_ParamFromIV(cipherMech, aIV); |
|
52 if (!param) |
|
53 return NS_ERROR_FAILURE; |
|
54 |
|
55 mContext = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, |
|
56 symkey, param); |
|
57 |
|
58 SECITEM_FreeItem(param, true); |
|
59 |
|
60 // Something went wrong if mContext doesn't exist. |
|
61 if (!mContext) |
|
62 return NS_ERROR_FAILURE; |
|
63 |
|
64 // Everything went ok. |
|
65 mValue.Truncate(); |
|
66 return NS_OK; |
|
67 } |
|
68 |
|
69 ///////////////////////////////////////////////////////////////////////////// |
|
70 // nsIStreamCipher |
|
71 |
|
72 NS_IMETHODIMP nsStreamCipher::Init(nsIKeyObject *aKey) |
|
73 { |
|
74 return InitWithIV_(aKey, nullptr); |
|
75 } |
|
76 |
|
77 NS_IMETHODIMP nsStreamCipher::InitWithIV(nsIKeyObject *aKey, |
|
78 const uint8_t *aIV, uint32_t aIVLen) |
|
79 { |
|
80 SECItem IV; |
|
81 IV.data = (unsigned char*)aIV; |
|
82 IV.len = aIVLen; |
|
83 return InitWithIV_(aKey, &IV); |
|
84 } |
|
85 |
|
86 NS_IMETHODIMP nsStreamCipher::Update(const uint8_t *aData, uint32_t aLen) |
|
87 { |
|
88 if (!mContext) |
|
89 return NS_ERROR_NOT_INITIALIZED; |
|
90 |
|
91 unsigned char* output = new unsigned char[aLen]; |
|
92 unsigned char* input = (unsigned char*)aData; |
|
93 |
|
94 int32_t setLen; |
|
95 |
|
96 #ifdef DEBUG |
|
97 SECStatus rv = |
|
98 #endif |
|
99 PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen); |
|
100 NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); |
|
101 NS_ASSERTION((uint32_t)setLen == aLen, "data length should not change"); |
|
102 |
|
103 mValue.Append((const char*)output, aLen); |
|
104 |
|
105 delete [] output; |
|
106 |
|
107 return NS_OK; |
|
108 } |
|
109 |
|
110 NS_IMETHODIMP nsStreamCipher::UpdateFromStream(nsIInputStream *aStream, |
|
111 int32_t aLen) |
|
112 { |
|
113 if (!mContext) |
|
114 return NS_ERROR_NOT_INITIALIZED; |
|
115 |
|
116 nsCString inputString; |
|
117 nsresult rv = NS_ConsumeStream(aStream, aLen, inputString); |
|
118 NS_ENSURE_SUCCESS(rv, rv); |
|
119 |
|
120 return UpdateFromString(inputString); |
|
121 } |
|
122 |
|
123 NS_IMETHODIMP nsStreamCipher::UpdateFromString(const nsACString& aInput) |
|
124 { |
|
125 if (!mContext) |
|
126 return NS_ERROR_NOT_INITIALIZED; |
|
127 |
|
128 const nsCString& flatInput = PromiseFlatCString(aInput); |
|
129 unsigned char* input = (unsigned char*)flatInput.get(); |
|
130 uint32_t len = aInput.Length(); |
|
131 |
|
132 unsigned char* output = new unsigned char[len]; |
|
133 |
|
134 int32_t setLen; |
|
135 |
|
136 #ifdef DEBUG |
|
137 SECStatus rv = |
|
138 #endif |
|
139 PK11_CipherOp(mContext, output, &setLen, len, input, len); |
|
140 NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); |
|
141 NS_ASSERTION((uint32_t)setLen == len, "data length should not change"); |
|
142 |
|
143 mValue.Append((const char*)output, len); |
|
144 delete [] output; |
|
145 |
|
146 return NS_OK; |
|
147 } |
|
148 |
|
149 NS_IMETHODIMP nsStreamCipher::Finish(bool aASCII, nsACString & _retval) |
|
150 { |
|
151 if (!mContext) |
|
152 return NS_ERROR_NOT_INITIALIZED; |
|
153 |
|
154 if (aASCII) { |
|
155 char *asciiData = BTOA_DataToAscii((unsigned char*)(mValue.get()), |
|
156 mValue.Length()); |
|
157 _retval.Assign(asciiData); |
|
158 PORT_Free(asciiData); |
|
159 } else { |
|
160 _retval.Assign(mValue); |
|
161 } |
|
162 |
|
163 return NS_OK; |
|
164 } |
|
165 |
|
166 NS_IMETHODIMP nsStreamCipher::Discard(int32_t aLen) |
|
167 { |
|
168 if (!mContext) |
|
169 return NS_ERROR_NOT_INITIALIZED; |
|
170 |
|
171 unsigned char* output = new unsigned char[aLen]; |
|
172 unsigned char* input = new unsigned char[aLen]; |
|
173 |
|
174 int32_t setLen; |
|
175 |
|
176 #ifdef DEBUG |
|
177 SECStatus rv = |
|
178 #endif |
|
179 PK11_CipherOp(mContext, output, &setLen, aLen, input, aLen); |
|
180 NS_ASSERTION(rv == SECSuccess, "failed to encrypt"); |
|
181 NS_ASSERTION(setLen == aLen, "data length should not change"); |
|
182 |
|
183 delete [] output; |
|
184 delete [] input; |
|
185 return NS_OK; |
|
186 } |