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