1// Copyright 2014 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. 4 5#include "base/base64.h" 6#include "base/files/file_path.h" 7#include "base/files/scoped_temp_dir.h" 8#include "crypto/sha2.h" 9#include "extensions/browser/computed_hashes.h" 10#include "testing/gtest/include/gtest/gtest.h" 11 12namespace { 13 14// Helper to return base64 encode result by value. 15std::string Base64Encode(const std::string& data) { 16 std::string result; 17 base::Base64Encode(data, &result); 18 return result; 19} 20 21} // namespace 22 23namespace extensions { 24 25TEST(ComputedHashes, ComputedHashes) { 26 base::ScopedTempDir scoped_dir; 27 ASSERT_TRUE(scoped_dir.CreateUniqueTempDir()); 28 base::FilePath computed_hashes = 29 scoped_dir.path().AppendASCII("computed_hashes.json"); 30 31 // We'll add hashes for 2 files, one of which uses a subdirectory 32 // path. The first file will have a list of 1 block hash, and the 33 // second file will have 2 block hashes. 34 base::FilePath path1(FILE_PATH_LITERAL("foo.txt")); 35 base::FilePath path2 = 36 base::FilePath(FILE_PATH_LITERAL("foo")).AppendASCII("bar.txt"); 37 std::vector<std::string> hashes1; 38 std::vector<std::string> hashes2; 39 hashes1.push_back(crypto::SHA256HashString("first")); 40 hashes2.push_back(crypto::SHA256HashString("second")); 41 hashes2.push_back(crypto::SHA256HashString("third")); 42 43 // Write them into the file. 44 ComputedHashes::Writer writer; 45 writer.AddHashes(path1, 4096, hashes1); 46 writer.AddHashes(path2, 2048, hashes2); 47 EXPECT_TRUE(writer.WriteToFile(computed_hashes)); 48 49 // Now read them back again and assert that we got what we wrote. 50 ComputedHashes::Reader reader; 51 std::vector<std::string> read_hashes1; 52 std::vector<std::string> read_hashes2; 53 EXPECT_TRUE(reader.InitFromFile(computed_hashes)); 54 55 int block_size = 0; 56 EXPECT_TRUE(reader.GetHashes(path1, &block_size, &read_hashes1)); 57 EXPECT_EQ(block_size, 4096); 58 block_size = 0; 59 EXPECT_TRUE(reader.GetHashes(path2, &block_size, &read_hashes2)); 60 EXPECT_EQ(block_size, 2048); 61 62 EXPECT_EQ(hashes1, read_hashes1); 63 EXPECT_EQ(hashes2, read_hashes2); 64 65 // Make sure we can lookup hashes for a file using incorrect case 66 base::FilePath path1_badcase(FILE_PATH_LITERAL("FoO.txt")); 67 std::vector<std::string> read_hashes1_badcase; 68 EXPECT_TRUE( 69 reader.GetHashes(path1_badcase, &block_size, &read_hashes1_badcase)); 70 EXPECT_EQ(block_size, 4096); 71 EXPECT_EQ(hashes1, read_hashes1_badcase); 72 73 // Finally make sure that we can retrieve the hashes for the subdir 74 // path even when that path contains forward slashes (on windows). 75 base::FilePath path2_fwd_slashes = 76 base::FilePath::FromUTF8Unsafe("foo/bar.txt"); 77 block_size = 0; 78 EXPECT_TRUE(reader.GetHashes(path2_fwd_slashes, &block_size, &read_hashes2)); 79 EXPECT_EQ(hashes2, read_hashes2); 80} 81 82// Note: the expected hashes used in this test were generated using linux 83// command line tools. E.g., from a bash prompt: 84// $ printf "hello world" | openssl dgst -sha256 -binary | base64 85// 86// The file with multiple-blocks expectations were generated by doing: 87// $ for i in `seq 500 ; do printf "hello world" ; done > hello.txt 88// $ dd if=hello.txt bs=4096 count=1 | openssl dgst -sha256 -binary | base64 89// $ dd if=hello.txt skip=1 bs=4096 count=1 | 90// openssl dgst -sha256 -binary | base64 91TEST(ComputedHashes, ComputeHashesForContent) { 92 const int block_size = 4096; 93 94 // Simple short input. 95 std::string content1 = "hello world"; 96 std::string content1_expected_hash = 97 "uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek="; 98 std::vector<std::string> hashes1; 99 ComputedHashes::ComputeHashesForContent(content1, block_size, &hashes1); 100 ASSERT_EQ(1u, hashes1.size()); 101 EXPECT_EQ(content1_expected_hash, Base64Encode(hashes1[0])); 102 103 // Multiple blocks input. 104 std::string content2; 105 for (int i = 0; i < 500; i++) 106 content2 += "hello world"; 107 const char* content2_expected_hashes[] = { 108 "bvtt5hXo8xvHrlzGAhhoqPL/r+4zJXHx+6wAvkv15V8=", 109 "lTD45F7P6I/HOdi8u7FLRA4qzAYL+7xSNVeusG6MJI0="}; 110 std::vector<std::string> hashes2; 111 ComputedHashes::ComputeHashesForContent(content2, block_size, &hashes2); 112 ASSERT_EQ(2u, hashes2.size()); 113 EXPECT_EQ(content2_expected_hashes[0], Base64Encode(hashes2[0])); 114 EXPECT_EQ(content2_expected_hashes[1], Base64Encode(hashes2[1])); 115 116 // Now an empty input. 117 std::string content3; 118 std::vector<std::string> hashes3; 119 ComputedHashes::ComputeHashesForContent(content3, block_size, &hashes3); 120 ASSERT_EQ(1u, hashes3.size()); 121 ASSERT_EQ(std::string("47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="), 122 Base64Encode(hashes3[0])); 123} 124 125} // namespace extensions 126