|
1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 // This header file defines the storage types of the actual safebrowsing |
|
7 // chunk data, which may be either 32-bit hashes or complete 256-bit hashes. |
|
8 // Chunk numbers are represented in ChunkSet.h. |
|
9 |
|
10 #ifndef SBEntries_h__ |
|
11 #define SBEntries_h__ |
|
12 |
|
13 #include "nsTArray.h" |
|
14 #include "nsString.h" |
|
15 #include "nsICryptoHash.h" |
|
16 #include "nsNetUtil.h" |
|
17 |
|
18 #if DEBUG |
|
19 #include "plbase64.h" |
|
20 #endif |
|
21 |
|
22 namespace mozilla { |
|
23 namespace safebrowsing { |
|
24 |
|
25 #define PREFIX_SIZE 4 |
|
26 #define COMPLETE_SIZE 32 |
|
27 |
|
28 // This is the struct that contains 4-byte hash prefixes. |
|
29 template <uint32_t S, class Comparator> |
|
30 struct SafebrowsingHash |
|
31 { |
|
32 static const uint32_t sHashSize = S; |
|
33 typedef SafebrowsingHash<S, Comparator> self_type; |
|
34 uint8_t buf[S]; |
|
35 |
|
36 nsresult FromPlaintext(const nsACString& aPlainText, nsICryptoHash* aHash) { |
|
37 // From the protocol doc: |
|
38 // Each entry in the chunk is composed |
|
39 // of the SHA 256 hash of a suffix/prefix expression. |
|
40 |
|
41 nsresult rv = aHash->Init(nsICryptoHash::SHA256); |
|
42 NS_ENSURE_SUCCESS(rv, rv); |
|
43 |
|
44 rv = aHash->Update |
|
45 (reinterpret_cast<const uint8_t*>(aPlainText.BeginReading()), |
|
46 aPlainText.Length()); |
|
47 NS_ENSURE_SUCCESS(rv, rv); |
|
48 |
|
49 nsAutoCString hashed; |
|
50 rv = aHash->Finish(false, hashed); |
|
51 NS_ENSURE_SUCCESS(rv, rv); |
|
52 |
|
53 NS_ASSERTION(hashed.Length() >= sHashSize, |
|
54 "not enough characters in the hash"); |
|
55 |
|
56 memcpy(buf, hashed.BeginReading(), sHashSize); |
|
57 |
|
58 return NS_OK; |
|
59 } |
|
60 |
|
61 void Assign(const nsACString& aStr) { |
|
62 NS_ASSERTION(aStr.Length() >= sHashSize, |
|
63 "string must be at least sHashSize characters long"); |
|
64 memcpy(buf, aStr.BeginReading(), sHashSize); |
|
65 } |
|
66 |
|
67 int Compare(const self_type& aOther) const { |
|
68 return Comparator::Compare(buf, aOther.buf); |
|
69 } |
|
70 |
|
71 bool operator==(const self_type& aOther) const { |
|
72 return Comparator::Compare(buf, aOther.buf) == 0; |
|
73 } |
|
74 |
|
75 bool operator!=(const self_type& aOther) const { |
|
76 return Comparator::Compare(buf, aOther.buf) != 0; |
|
77 } |
|
78 |
|
79 bool operator<(const self_type& aOther) const { |
|
80 return Comparator::Compare(buf, aOther.buf) < 0; |
|
81 } |
|
82 |
|
83 #ifdef DEBUG |
|
84 void ToString(nsACString& aStr) const { |
|
85 uint32_t len = ((sHashSize + 2) / 3) * 4; |
|
86 aStr.SetCapacity(len + 1); |
|
87 PL_Base64Encode((char*)buf, sHashSize, aStr.BeginWriting()); |
|
88 aStr.BeginWriting()[len] = '\0'; |
|
89 } |
|
90 |
|
91 void ToHexString(nsACString& aStr) const { |
|
92 static const char* const lut = "0123456789ABCDEF"; |
|
93 // 32 bytes is the longest hash |
|
94 size_t len = 32; |
|
95 |
|
96 aStr.SetCapacity(2 * len); |
|
97 for (size_t i = 0; i < len; ++i) { |
|
98 const char c = static_cast<const char>(buf[i]); |
|
99 aStr.Append(lut[(c >> 4) & 0x0F]); |
|
100 aStr.Append(lut[c & 15]); |
|
101 } |
|
102 } |
|
103 #endif |
|
104 uint32_t ToUint32() const { |
|
105 return *((uint32_t*)buf); |
|
106 } |
|
107 void FromUint32(uint32_t aHash) { |
|
108 *((uint32_t*)buf) = aHash; |
|
109 } |
|
110 }; |
|
111 |
|
112 class PrefixComparator { |
|
113 public: |
|
114 static int Compare(const uint8_t* a, const uint8_t* b) { |
|
115 uint32_t first = *((uint32_t*)a); |
|
116 uint32_t second = *((uint32_t*)b); |
|
117 if (first > second) { |
|
118 return 1; |
|
119 } else if (first == second) { |
|
120 return 0; |
|
121 } else { |
|
122 return -1; |
|
123 } |
|
124 } |
|
125 }; |
|
126 // Use this for 4-byte hashes |
|
127 typedef SafebrowsingHash<PREFIX_SIZE, PrefixComparator> Prefix; |
|
128 typedef nsTArray<Prefix> PrefixArray; |
|
129 |
|
130 class CompletionComparator { |
|
131 public: |
|
132 static int Compare(const uint8_t* a, const uint8_t* b) { |
|
133 return memcmp(a, b, COMPLETE_SIZE); |
|
134 } |
|
135 }; |
|
136 // Use this for 32-byte hashes |
|
137 typedef SafebrowsingHash<COMPLETE_SIZE, CompletionComparator> Completion; |
|
138 typedef nsTArray<Completion> CompletionArray; |
|
139 |
|
140 struct AddPrefix { |
|
141 // The truncated hash. |
|
142 Prefix prefix; |
|
143 // The chunk number to which it belongs. |
|
144 uint32_t addChunk; |
|
145 |
|
146 AddPrefix() : addChunk(0) {} |
|
147 |
|
148 // Returns the chunk number. |
|
149 uint32_t Chunk() const { return addChunk; } |
|
150 const Prefix &PrefixHash() const { return prefix; } |
|
151 |
|
152 template<class T> |
|
153 int Compare(const T& other) const { |
|
154 int cmp = prefix.Compare(other.PrefixHash()); |
|
155 if (cmp != 0) { |
|
156 return cmp; |
|
157 } |
|
158 return addChunk - other.addChunk; |
|
159 } |
|
160 }; |
|
161 |
|
162 struct AddComplete { |
|
163 Completion complete; |
|
164 uint32_t addChunk; |
|
165 |
|
166 AddComplete() : addChunk(0) {} |
|
167 |
|
168 uint32_t Chunk() const { return addChunk; } |
|
169 // The 4-byte prefix of the sha256 hash. |
|
170 uint32_t ToUint32() const { return complete.ToUint32(); } |
|
171 // The 32-byte sha256 hash. |
|
172 const Completion &CompleteHash() const { return complete; } |
|
173 |
|
174 template<class T> |
|
175 int Compare(const T& other) const { |
|
176 int cmp = complete.Compare(other.CompleteHash()); |
|
177 if (cmp != 0) { |
|
178 return cmp; |
|
179 } |
|
180 return addChunk - other.addChunk; |
|
181 } |
|
182 }; |
|
183 |
|
184 struct SubPrefix { |
|
185 // The hash to subtract. |
|
186 Prefix prefix; |
|
187 // The chunk number of the add chunk to which the hash belonged. |
|
188 uint32_t addChunk; |
|
189 // The chunk number of this sub chunk. |
|
190 uint32_t subChunk; |
|
191 |
|
192 SubPrefix(): addChunk(0), subChunk(0) {} |
|
193 |
|
194 uint32_t Chunk() const { return subChunk; } |
|
195 uint32_t AddChunk() const { return addChunk; } |
|
196 const Prefix &PrefixHash() const { return prefix; } |
|
197 |
|
198 template<class T> |
|
199 // Returns 0 if and only if the chunks are the same in every way. |
|
200 int Compare(const T& aOther) const { |
|
201 int cmp = prefix.Compare(aOther.PrefixHash()); |
|
202 if (cmp != 0) |
|
203 return cmp; |
|
204 if (addChunk != aOther.addChunk) |
|
205 return addChunk - aOther.addChunk; |
|
206 return subChunk - aOther.subChunk; |
|
207 } |
|
208 |
|
209 template<class T> |
|
210 int CompareAlt(const T& aOther) const { |
|
211 Prefix other; |
|
212 other.FromUint32(aOther.ToUint32()); |
|
213 int cmp = prefix.Compare(other); |
|
214 if (cmp != 0) |
|
215 return cmp; |
|
216 return addChunk - aOther.addChunk; |
|
217 } |
|
218 }; |
|
219 |
|
220 struct SubComplete { |
|
221 Completion complete; |
|
222 uint32_t addChunk; |
|
223 uint32_t subChunk; |
|
224 |
|
225 SubComplete() : addChunk(0), subChunk(0) {} |
|
226 |
|
227 uint32_t Chunk() const { return subChunk; } |
|
228 uint32_t AddChunk() const { return addChunk; } |
|
229 const Completion &CompleteHash() const { return complete; } |
|
230 // The 4-byte prefix of the sha256 hash. |
|
231 uint32_t ToUint32() const { return complete.ToUint32(); } |
|
232 |
|
233 int Compare(const SubComplete& aOther) const { |
|
234 int cmp = complete.Compare(aOther.complete); |
|
235 if (cmp != 0) |
|
236 return cmp; |
|
237 if (addChunk != aOther.addChunk) |
|
238 return addChunk - aOther.addChunk; |
|
239 return subChunk - aOther.subChunk; |
|
240 } |
|
241 }; |
|
242 |
|
243 typedef FallibleTArray<AddPrefix> AddPrefixArray; |
|
244 typedef FallibleTArray<AddComplete> AddCompleteArray; |
|
245 typedef FallibleTArray<SubPrefix> SubPrefixArray; |
|
246 typedef FallibleTArray<SubComplete> SubCompleteArray; |
|
247 |
|
248 /** |
|
249 * Compares chunks by their add chunk, then their prefix. |
|
250 */ |
|
251 template<class T> |
|
252 class EntryCompare { |
|
253 public: |
|
254 typedef T elem_type; |
|
255 static int Compare(const void* e1, const void* e2) { |
|
256 const elem_type* a = static_cast<const elem_type*>(e1); |
|
257 const elem_type* b = static_cast<const elem_type*>(e2); |
|
258 return a->Compare(*b); |
|
259 } |
|
260 }; |
|
261 |
|
262 /** |
|
263 * Sort an array of store entries. nsTArray::Sort uses Equal/LessThan |
|
264 * to sort, this does a single Compare so it's a bit quicker over the |
|
265 * large sorts we do. |
|
266 */ |
|
267 template<class T, class Alloc> |
|
268 void |
|
269 EntrySort(nsTArray_Impl<T, Alloc>& aArray) |
|
270 { |
|
271 qsort(aArray.Elements(), aArray.Length(), sizeof(T), |
|
272 EntryCompare<T>::Compare); |
|
273 } |
|
274 |
|
275 template<class T, class Alloc> |
|
276 nsresult |
|
277 ReadTArray(nsIInputStream* aStream, nsTArray_Impl<T, Alloc>* aArray, uint32_t aNumElements) |
|
278 { |
|
279 aArray->SetLength(aNumElements); |
|
280 |
|
281 void *buffer = aArray->Elements(); |
|
282 nsresult rv = NS_ReadInputStreamToBuffer(aStream, &buffer, |
|
283 (aNumElements * sizeof(T))); |
|
284 NS_ENSURE_SUCCESS(rv, rv); |
|
285 return NS_OK; |
|
286 } |
|
287 |
|
288 template<class T> |
|
289 nsresult |
|
290 ReadTArray(nsIInputStream* aStream, FallibleTArray<T>* aArray, uint32_t aNumElements) |
|
291 { |
|
292 if (!aArray->SetLength(aNumElements)) |
|
293 return NS_ERROR_OUT_OF_MEMORY; |
|
294 |
|
295 void *buffer = aArray->Elements(); |
|
296 nsresult rv = NS_ReadInputStreamToBuffer(aStream, &buffer, |
|
297 (aNumElements * sizeof(T))); |
|
298 NS_ENSURE_SUCCESS(rv, rv); |
|
299 return NS_OK; |
|
300 } |
|
301 |
|
302 template<class T, class Alloc> |
|
303 nsresult |
|
304 WriteTArray(nsIOutputStream* aStream, nsTArray_Impl<T, Alloc>& aArray) |
|
305 { |
|
306 uint32_t written; |
|
307 return aStream->Write(reinterpret_cast<char*>(aArray.Elements()), |
|
308 aArray.Length() * sizeof(T), |
|
309 &written); |
|
310 } |
|
311 |
|
312 } // namespace safebrowsing |
|
313 } // namespace mozilla |
|
314 #endif // SBEntries_h__ |