Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / safe_browsing / zip_analyzer.cc
blobbf1bf069d160e1bbc4837b98d6507eca1c58d8d7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/safe_browsing/zip_analyzer.h"
7 #include <set>
9 #include "base/i18n/streaming_utf8_validator.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
13 #include "chrome/common/safe_browsing/csd.pb.h"
14 #include "chrome/common/safe_browsing/download_protection_util.h"
15 #include "chrome/common/safe_browsing/zip_analyzer_results.h"
16 #include "crypto/secure_hash.h"
17 #include "crypto/sha2.h"
18 #include "third_party/zlib/google/zip_reader.h"
20 namespace safe_browsing {
21 namespace zip_analyzer {
23 namespace {
25 // A writer delegate that computes a SHA-256 hash digest over the data while
26 // writing it to a file.
27 class HashingFileWriter : public zip::FileWriterDelegate {
28 public:
29 explicit HashingFileWriter(base::File* file);
31 // zip::FileWriterDelegate methods:
32 bool WriteBytes(const char* data, int num_bytes) override;
34 void ComputeDigest(uint8_t* digest, size_t digest_length);
36 private:
37 scoped_ptr<crypto::SecureHash> sha256_;
39 DISALLOW_COPY_AND_ASSIGN(HashingFileWriter);
42 HashingFileWriter::HashingFileWriter(base::File* file)
43 : zip::FileWriterDelegate(file),
44 sha256_(crypto::SecureHash::Create(crypto::SecureHash::SHA256)) {
47 bool HashingFileWriter::WriteBytes(const char* data, int num_bytes) {
48 if (!zip::FileWriterDelegate::WriteBytes(data, num_bytes))
49 return false;
50 sha256_->Update(data, num_bytes);
51 return true;
54 void HashingFileWriter::ComputeDigest(uint8_t* digest, size_t digest_length) {
55 sha256_->Finish(digest, digest_length);
58 void AnalyzeContainedFile(
59 const scoped_refptr<BinaryFeatureExtractor>& binary_feature_extractor,
60 const base::FilePath& file_path,
61 zip::ZipReader* reader,
62 base::File* temp_file,
63 ClientDownloadRequest_ArchivedBinary* archived_binary) {
64 std::string file_basename(file_path.BaseName().AsUTF8Unsafe());
65 if (base::StreamingUtf8Validator::Validate(file_basename))
66 archived_binary->set_file_basename(file_basename);
67 archived_binary->set_download_type(
68 download_protection_util::GetDownloadType(file_path));
69 archived_binary->set_length(reader->current_entry_info()->original_size());
70 HashingFileWriter writer(temp_file);
71 if (reader->ExtractCurrentEntry(&writer)) {
72 uint8_t digest[crypto::kSHA256Length];
73 writer.ComputeDigest(&digest[0], arraysize(digest));
74 archived_binary->mutable_digests()->set_sha256(&digest[0],
75 arraysize(digest));
76 if (!binary_feature_extractor->ExtractImageFeaturesFromFile(
77 temp_file->Duplicate(),
78 BinaryFeatureExtractor::kDefaultOptions,
79 archived_binary->mutable_image_headers(),
80 archived_binary->mutable_signature()->mutable_signed_data())) {
81 archived_binary->clear_image_headers();
82 archived_binary->clear_signature();
83 } else if (!archived_binary->signature().signed_data_size()) {
84 // No SignedData blobs were extracted, so clear the signature field.
85 archived_binary->clear_signature();
90 } // namespace
92 void AnalyzeZipFile(base::File zip_file,
93 base::File temp_file,
94 Results* results) {
95 std::set<base::FilePath::StringType> archived_archive_filetypes;
96 scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor(
97 new BinaryFeatureExtractor());
98 zip::ZipReader reader;
99 if (!reader.OpenFromPlatformFile(zip_file.GetPlatformFile())) {
100 DVLOG(1) << "Failed to open zip file";
101 return;
104 bool advanced = true;
105 for (; reader.HasMore(); advanced = reader.AdvanceToNextEntry()) {
106 if (!advanced) {
107 DVLOG(1) << "Could not advance to next entry, aborting zip scan.";
108 return;
110 if (!reader.OpenCurrentEntryInZip()) {
111 DVLOG(1) << "Failed to open current entry in zip file";
112 continue;
114 const base::FilePath& file = reader.current_entry_info()->file_path();
115 if (download_protection_util::IsArchiveFile(file)) {
116 DVLOG(2) << "Downloaded a zipped archive: " << file.value();
117 results->has_archive = true;
118 archived_archive_filetypes.insert(file.FinalExtension());
119 } else if (download_protection_util::IsSupportedBinaryFile(file)) {
120 DVLOG(2) << "Downloaded a zipped executable: " << file.value();
121 results->has_executable = true;
122 AnalyzeContainedFile(binary_feature_extractor, file, &reader, &temp_file,
123 results->archived_binary.Add());
124 } else {
125 DVLOG(3) << "Ignoring non-binary file: " << file.value();
128 results->archived_archive_filetypes.assign(archived_archive_filetypes.begin(),
129 archived_archive_filetypes.end());
130 results->success = true;
133 } // namespace zip_analyzer
134 } // namespace safe_browsing