1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/base64.h"
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/file_path.h"
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/files/scoped_temp_dir.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "crypto/sha2.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "extensions/browser/computed_hashes.h"
10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "testing/gtest/include/gtest/gtest.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace {
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Helper to return base64 encode result by value.
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)std::string Base64Encode(const std::string& data) {
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string result;
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::Base64Encode(data, &result);
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return result;
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace extensions {
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
25116680a4aac90f2aa7413d9095a592090648e557Ben MurdochTEST(ComputedHashes, ComputedHashes) {
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ScopedTempDir scoped_dir;
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ASSERT_TRUE(scoped_dir.CreateUniqueTempDir());
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath computed_hashes =
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      scoped_dir.path().AppendASCII("computed_hashes.json");
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // We'll add hashes for 2 files, one of which uses a subdirectory
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // path. The first file will have a list of 1 block hash, and the
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // second file will have 2 block hashes.
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath path1(FILE_PATH_LITERAL("foo.txt"));
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath path2 =
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::FilePath(FILE_PATH_LITERAL("foo")).AppendASCII("bar.txt");
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> hashes1;
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> hashes2;
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  hashes1.push_back(crypto::SHA256HashString("first"));
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  hashes2.push_back(crypto::SHA256HashString("second"));
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  hashes2.push_back(crypto::SHA256HashString("third"));
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Write them into the file.
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ComputedHashes::Writer writer;
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  writer.AddHashes(path1, 4096, hashes1);
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  writer.AddHashes(path2, 2048, hashes2);
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(writer.WriteToFile(computed_hashes));
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Now read them back again and assert that we got what we wrote.
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  ComputedHashes::Reader reader;
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> read_hashes1;
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<std::string> read_hashes2;
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(reader.InitFromFile(computed_hashes));
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int block_size = 0;
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(reader.GetHashes(path1, &block_size, &read_hashes1));
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(block_size, 4096);
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  block_size = 0;
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(reader.GetHashes(path2, &block_size, &read_hashes2));
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(block_size, 2048);
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(hashes1, read_hashes1);
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(hashes2, read_hashes2);
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
651675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  // Make sure we can lookup hashes for a file using incorrect case
661675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  base::FilePath path1_badcase(FILE_PATH_LITERAL("FoO.txt"));
671675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  std::vector<std::string> read_hashes1_badcase;
681675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  EXPECT_TRUE(
691675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch      reader.GetHashes(path1_badcase, &block_size, &read_hashes1_badcase));
701675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  EXPECT_EQ(block_size, 4096);
711675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch  EXPECT_EQ(hashes1, read_hashes1_badcase);
721675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Finally make sure that we can retrieve the hashes for the subdir
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // path even when that path contains forward slashes (on windows).
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::FilePath path2_fwd_slashes =
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  block_size = 0;
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_TRUE(reader.GetHashes(path2_fwd_slashes, &block_size, &read_hashes2));
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  EXPECT_EQ(hashes2, read_hashes2);
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Note: the expected hashes used in this test were generated using linux
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// command line tools. E.g., from a bash prompt:
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//  $ printf "hello world" | openssl dgst -sha256 -binary | base64
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The file with multiple-blocks expectations were generated by doing:
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// $ for i in `seq 500 ; do printf "hello world" ; done > hello.txt
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// $ dd if=hello.txt bs=4096 count=1 | openssl dgst -sha256 -binary | base64
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// $ dd if=hello.txt skip=1 bs=4096 count=1 |
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   openssl dgst -sha256 -binary | base64
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST(ComputedHashes, ComputeHashesForContent) {
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const int block_size = 4096;
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Simple short input.
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string content1 = "hello world";
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string content1_expected_hash =
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=";
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> hashes1;
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ComputedHashes::ComputeHashesForContent(content1, block_size, &hashes1);
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_EQ(1u, hashes1.size());
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(content1_expected_hash, Base64Encode(hashes1[0]));
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Multiple blocks input.
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string content2;
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (int i = 0; i < 500; i++)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    content2 += "hello world";
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const char* content2_expected_hashes[] = {
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "bvtt5hXo8xvHrlzGAhhoqPL/r+4zJXHx+6wAvkv15V8=",
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "lTD45F7P6I/HOdi8u7FLRA4qzAYL+7xSNVeusG6MJI0="};
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> hashes2;
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ComputedHashes::ComputeHashesForContent(content2, block_size, &hashes2);
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_EQ(2u, hashes2.size());
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(content2_expected_hashes[0], Base64Encode(hashes2[0]));
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(content2_expected_hashes[1], Base64Encode(hashes2[1]));
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Now an empty input.
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string content3;
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> hashes3;
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ComputedHashes::ComputeHashesForContent(content3, block_size, &hashes3);
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_EQ(1u, hashes3.size());
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_EQ(std::string("47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="),
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            Base64Encode(hashes3[0]));
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace extensions
126