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. 4 5 #include "chrome/utility/chrome_content_utility_client.h" 6 7 #include "base/base64.h" 8 #include "base/bind.h" 9 #include "base/command_line.h" 10 #include "base/files/file_path.h" 11 #include "base/json/json_reader.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/path_service.h" 14 #include "base/time/time.h" 15 #include "chrome/common/chrome_utility_messages.h" 16 #include "chrome/common/extensions/chrome_extensions_client.h" 17 #include "chrome/common/extensions/update_manifest.h" 18 #include "chrome/common/safe_browsing/zip_analyzer.h" 19 #include "chrome/utility/chrome_content_utility_ipc_whitelist.h" 20 #include "chrome/utility/extensions/unpacker.h" 21 #include "chrome/utility/image_writer/image_writer_handler.h" 22 #include "chrome/utility/profile_import_handler.h" 23 #include "chrome/utility/web_resource_unpacker.h" 24 #include "content/public/child/image_decoder_utils.h" 25 #include "content/public/common/content_paths.h" 26 #include "content/public/common/content_switches.h" 27 #include "content/public/utility/utility_thread.h" 28 #include "courgette/courgette.h" 29 #include "courgette/third_party/bsdiff.h" 30 #include "extensions/common/extension.h" 31 #include "extensions/common/extension_l10n_util.h" 32 #include "extensions/common/manifest.h" 33 #include "media/base/media.h" 34 #include "media/base/media_file_checker.h" 35 #include "third_party/skia/include/core/SkBitmap.h" 36 #include "third_party/zlib/google/zip.h" 37 #include "ui/base/ui_base_switches.h" 38 #include "ui/gfx/codec/jpeg_codec.h" 39 #include "ui/gfx/rect.h" 40 #include "ui/gfx/size.h" 41 42 #if defined(OS_WIN) 43 #include "chrome/common/extensions/api/networking_private/networking_private_crypto.h" 44 #include "chrome/utility/media_galleries/itunes_pref_parser_win.h" 45 #include "components/wifi/wifi_service.h" 46 #endif // defined(OS_WIN) 47 48 #if defined(OS_MACOSX) 49 #include "chrome/utility/media_galleries/iphoto_library_parser.h" 50 #endif // defined(OS_MACOSX) 51 52 #if defined(OS_WIN) || defined(OS_MACOSX) 53 #include "chrome/utility/media_galleries/iapps_xml_utils.h" 54 #include "chrome/utility/media_galleries/itunes_library_parser.h" 55 #include "chrome/utility/media_galleries/picasa_album_table_reader.h" 56 #include "chrome/utility/media_galleries/picasa_albums_indexer.h" 57 #endif // defined(OS_WIN) || defined(OS_MACOSX) 58 59 #if !defined(OS_ANDROID) && !defined(OS_IOS) 60 #include "chrome/common/media_galleries/metadata_types.h" 61 #include "chrome/utility/media_galleries/image_metadata_extractor.h" 62 #include "chrome/utility/media_galleries/ipc_data_source.h" 63 #include "chrome/utility/media_galleries/media_metadata_parser.h" 64 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 65 66 #if defined(ENABLE_FULL_PRINTING) 67 #include "chrome/utility/printing_handler.h" 68 #endif 69 70 #if defined(ENABLE_MDNS) 71 #include "chrome/utility/local_discovery/service_discovery_message_handler.h" 72 #endif 73 74 namespace { 75 76 bool Send(IPC::Message* message) { 77 return content::UtilityThread::Get()->Send(message); 78 } 79 80 void ReleaseProcessIfNeeded() { 81 content::UtilityThread::Get()->ReleaseProcessIfNeeded(); 82 } 83 84 #if !defined(OS_ANDROID) && !defined(OS_IOS) 85 void FinishParseMediaMetadata( 86 metadata::MediaMetadataParser* parser, 87 const extensions::api::media_galleries::MediaMetadata& metadata, 88 const std::vector<metadata::AttachedImage>& attached_images) { 89 Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished( 90 true, *metadata.ToValue(), attached_images)); 91 ReleaseProcessIfNeeded(); 92 } 93 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 94 95 } // namespace 96 97 ChromeContentUtilityClient::ChromeContentUtilityClient() 98 : filter_messages_(false) { 99 #if !defined(OS_ANDROID) 100 handlers_.push_back(new ProfileImportHandler()); 101 #endif 102 103 #if defined(ENABLE_FULL_PRINTING) 104 handlers_.push_back(new PrintingHandler()); 105 #endif 106 107 #if defined(ENABLE_MDNS) 108 if (CommandLine::ForCurrentProcess()->HasSwitch( 109 switches::kUtilityProcessEnableMDns)) { 110 handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler()); 111 } 112 #endif 113 114 handlers_.push_back(new image_writer::ImageWriterHandler()); 115 } 116 117 ChromeContentUtilityClient::~ChromeContentUtilityClient() { 118 } 119 120 void ChromeContentUtilityClient::UtilityThreadStarted() { 121 CommandLine* command_line = CommandLine::ForCurrentProcess(); 122 std::string lang = command_line->GetSwitchValueASCII(switches::kLang); 123 if (!lang.empty()) 124 extension_l10n_util::SetProcessLocale(lang); 125 126 if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) { 127 message_id_whitelist_.insert(kMessageWhitelist, 128 kMessageWhitelist + kMessageWhitelistSize); 129 filter_messages_ = true; 130 } 131 } 132 133 bool ChromeContentUtilityClient::OnMessageReceived( 134 const IPC::Message& message) { 135 if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type())) 136 return false; 137 138 bool handled = true; 139 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message) 140 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension) 141 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackWebResource, 142 OnUnpackWebResource) 143 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseUpdateManifest, 144 OnParseUpdateManifest) 145 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage) 146 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImageBase64, OnDecodeImageBase64) 147 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage, 148 OnRobustJPEGDecodeImage) 149 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON) 150 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff, 151 OnPatchFileBsdiff) 152 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette, 153 OnPatchFileCourgette) 154 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing) 155 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection, 156 OnAnalyzeZipFileForDownloadProtection) 157 158 #if !defined(OS_ANDROID) && !defined(OS_IOS) 159 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CheckMediaFile, OnCheckMediaFile) 160 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata, 161 OnParseMediaMetadata) 162 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 163 164 #if defined(OS_CHROMEOS) 165 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile) 166 #endif // defined(OS_CHROMEOS) 167 168 #if defined(OS_WIN) 169 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesPrefXml, 170 OnParseITunesPrefXml) 171 #endif // defined(OS_WIN) 172 173 #if defined(OS_MACOSX) 174 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseIPhotoLibraryXmlFile, 175 OnParseIPhotoLibraryXmlFile) 176 #endif // defined(OS_MACOSX) 177 178 #if defined(OS_WIN) || defined(OS_MACOSX) 179 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseITunesLibraryXmlFile, 180 OnParseITunesLibraryXmlFile) 181 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParsePicasaPMPDatabase, 182 OnParsePicasaPMPDatabase) 183 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_IndexPicasaAlbumsContents, 184 OnIndexPicasaAlbumsContents) 185 #endif // defined(OS_WIN) || defined(OS_MACOSX) 186 187 #if defined(OS_WIN) 188 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetAndEncryptWiFiCredentials, 189 OnGetAndEncryptWiFiCredentials) 190 #endif // defined(OS_WIN) 191 192 IPC_MESSAGE_UNHANDLED(handled = false) 193 IPC_END_MESSAGE_MAP() 194 195 for (Handlers::iterator it = handlers_.begin(); 196 !handled && it != handlers_.end(); ++it) { 197 handled = (*it)->OnMessageReceived(message); 198 } 199 200 return handled; 201 } 202 203 // static 204 void ChromeContentUtilityClient::PreSandboxStartup() { 205 #if defined(ENABLE_FULL_PRINTING) 206 PrintingHandler::PreSandboxStartup(); 207 #endif 208 209 #if defined(ENABLE_MDNS) 210 if (CommandLine::ForCurrentProcess()->HasSwitch( 211 switches::kUtilityProcessEnableMDns)) { 212 local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup(); 213 } 214 #endif // ENABLE_MDNS 215 216 #if !defined(OS_ANDROID) && !defined(OS_IOS) 217 // Initialize libexif for image metadata parsing. 218 metadata::ImageMetadataExtractor::InitializeLibrary(); 219 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 220 221 // Load media libraries for media file validation. 222 base::FilePath media_path; 223 PathService::Get(content::DIR_MEDIA_LIBS, &media_path); 224 if (!media_path.empty()) 225 media::InitializeMediaLibrary(media_path); 226 } 227 228 void ChromeContentUtilityClient::OnUnpackExtension( 229 const base::FilePath& extension_path, 230 const std::string& extension_id, 231 int location, 232 int creation_flags) { 233 CHECK_GT(location, extensions::Manifest::INVALID_LOCATION); 234 CHECK_LT(location, extensions::Manifest::NUM_LOCATIONS); 235 extensions::ExtensionsClient::Set( 236 extensions::ChromeExtensionsClient::GetInstance()); 237 extensions::Unpacker unpacker( 238 extension_path, 239 extension_id, 240 static_cast<extensions::Manifest::Location>(location), 241 creation_flags); 242 if (unpacker.Run() && unpacker.DumpImagesToFile() && 243 unpacker.DumpMessageCatalogsToFile()) { 244 Send(new ChromeUtilityHostMsg_UnpackExtension_Succeeded( 245 *unpacker.parsed_manifest())); 246 } else { 247 Send(new ChromeUtilityHostMsg_UnpackExtension_Failed( 248 unpacker.error_message())); 249 } 250 251 ReleaseProcessIfNeeded(); 252 } 253 254 void ChromeContentUtilityClient::OnUnpackWebResource( 255 const std::string& resource_data) { 256 // Parse json data. 257 // TODO(mrc): Add the possibility of a template that controls parsing, and 258 // the ability to download and verify images. 259 WebResourceUnpacker unpacker(resource_data); 260 if (unpacker.Run()) { 261 Send(new ChromeUtilityHostMsg_UnpackWebResource_Succeeded( 262 *unpacker.parsed_json())); 263 } else { 264 Send(new ChromeUtilityHostMsg_UnpackWebResource_Failed( 265 unpacker.error_message())); 266 } 267 268 ReleaseProcessIfNeeded(); 269 } 270 271 void ChromeContentUtilityClient::OnParseUpdateManifest(const std::string& xml) { 272 UpdateManifest manifest; 273 if (!manifest.Parse(xml)) { 274 Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Failed( 275 manifest.errors())); 276 } else { 277 Send(new ChromeUtilityHostMsg_ParseUpdateManifest_Succeeded( 278 manifest.results())); 279 } 280 ReleaseProcessIfNeeded(); 281 } 282 283 void ChromeContentUtilityClient::OnDecodeImage( 284 const std::vector<unsigned char>& encoded_data) { 285 const SkBitmap& decoded_image = content::DecodeImage(&encoded_data[0], 286 gfx::Size(), 287 encoded_data.size()); 288 if (decoded_image.empty()) { 289 Send(new ChromeUtilityHostMsg_DecodeImage_Failed()); 290 } else { 291 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image)); 292 } 293 ReleaseProcessIfNeeded(); 294 } 295 296 void ChromeContentUtilityClient::OnDecodeImageBase64( 297 const std::string& encoded_string) { 298 std::string decoded_string; 299 300 if (!base::Base64Decode(encoded_string, &decoded_string)) { 301 Send(new ChromeUtilityHostMsg_DecodeImage_Failed()); 302 return; 303 } 304 305 std::vector<unsigned char> decoded_vector(decoded_string.size()); 306 for (size_t i = 0; i < decoded_string.size(); ++i) { 307 decoded_vector[i] = static_cast<unsigned char>(decoded_string[i]); 308 } 309 310 OnDecodeImage(decoded_vector); 311 } 312 313 #if defined(OS_CHROMEOS) 314 void ChromeContentUtilityClient::OnCreateZipFile( 315 const base::FilePath& src_dir, 316 const std::vector<base::FilePath>& src_relative_paths, 317 const base::FileDescriptor& dest_fd) { 318 bool succeeded = true; 319 320 // Check sanity of source relative paths. Reject if path is absolute or 321 // contains any attempt to reference a parent directory ("../" tricks). 322 for (std::vector<base::FilePath>::const_iterator iter = 323 src_relative_paths.begin(); iter != src_relative_paths.end(); 324 ++iter) { 325 if (iter->IsAbsolute() || iter->ReferencesParent()) { 326 succeeded = false; 327 break; 328 } 329 } 330 331 if (succeeded) 332 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd); 333 334 if (succeeded) 335 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded()); 336 else 337 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed()); 338 ReleaseProcessIfNeeded(); 339 } 340 #endif // defined(OS_CHROMEOS) 341 342 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage( 343 const std::vector<unsigned char>& encoded_data) { 344 // Our robust jpeg decoding is using IJG libjpeg. 345 if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG) { 346 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode( 347 &encoded_data[0], encoded_data.size())); 348 if (!decoded_image.get() || decoded_image->empty()) { 349 Send(new ChromeUtilityHostMsg_DecodeImage_Failed()); 350 } else { 351 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image)); 352 } 353 } else { 354 Send(new ChromeUtilityHostMsg_DecodeImage_Failed()); 355 } 356 ReleaseProcessIfNeeded(); 357 } 358 359 void ChromeContentUtilityClient::OnParseJSON(const std::string& json) { 360 int error_code; 361 std::string error; 362 base::Value* value = base::JSONReader::ReadAndReturnError( 363 json, base::JSON_PARSE_RFC, &error_code, &error); 364 if (value) { 365 base::ListValue wrapper; 366 wrapper.Append(value); 367 Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper)); 368 } else { 369 Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error)); 370 } 371 ReleaseProcessIfNeeded(); 372 } 373 374 void ChromeContentUtilityClient::OnPatchFileBsdiff( 375 const base::FilePath& input_file, 376 const base::FilePath& patch_file, 377 const base::FilePath& output_file) { 378 if (input_file.empty() || patch_file.empty() || output_file.empty()) { 379 Send(new ChromeUtilityHostMsg_PatchFile_Failed(-1)); 380 } else { 381 const int patch_status = courgette::ApplyBinaryPatch(input_file, 382 patch_file, 383 output_file); 384 if (patch_status != courgette::OK) 385 Send(new ChromeUtilityHostMsg_PatchFile_Failed(patch_status)); 386 else 387 Send(new ChromeUtilityHostMsg_PatchFile_Succeeded()); 388 } 389 ReleaseProcessIfNeeded(); 390 } 391 392 void ChromeContentUtilityClient::OnPatchFileCourgette( 393 const base::FilePath& input_file, 394 const base::FilePath& patch_file, 395 const base::FilePath& output_file) { 396 if (input_file.empty() || patch_file.empty() || output_file.empty()) { 397 Send(new ChromeUtilityHostMsg_PatchFile_Failed(-1)); 398 } else { 399 const int patch_status = courgette::ApplyEnsemblePatch( 400 input_file.value().c_str(), 401 patch_file.value().c_str(), 402 output_file.value().c_str()); 403 if (patch_status != courgette::C_OK) 404 Send(new ChromeUtilityHostMsg_PatchFile_Failed(patch_status)); 405 else 406 Send(new ChromeUtilityHostMsg_PatchFile_Succeeded()); 407 } 408 ReleaseProcessIfNeeded(); 409 } 410 411 void ChromeContentUtilityClient::OnStartupPing() { 412 Send(new ChromeUtilityHostMsg_ProcessStarted); 413 // Don't release the process, we assume further messages are on the way. 414 } 415 416 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection( 417 const IPC::PlatformFileForTransit& zip_file) { 418 safe_browsing::zip_analyzer::Results results; 419 safe_browsing::zip_analyzer::AnalyzeZipFile( 420 IPC::PlatformFileForTransitToFile(zip_file), &results); 421 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished( 422 results)); 423 ReleaseProcessIfNeeded(); 424 } 425 426 #if !defined(OS_ANDROID) && !defined(OS_IOS) 427 void ChromeContentUtilityClient::OnCheckMediaFile( 428 int64 milliseconds_of_decoding, 429 const IPC::PlatformFileForTransit& media_file) { 430 media::MediaFileChecker checker( 431 IPC::PlatformFileForTransitToFile(media_file)); 432 const bool check_success = checker.Start( 433 base::TimeDelta::FromMilliseconds(milliseconds_of_decoding)); 434 Send(new ChromeUtilityHostMsg_CheckMediaFile_Finished(check_success)); 435 ReleaseProcessIfNeeded(); 436 } 437 438 void ChromeContentUtilityClient::OnParseMediaMetadata( 439 const std::string& mime_type, int64 total_size, bool get_attached_images) { 440 // Only one IPCDataSource may be created and added to the list of handlers. 441 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size); 442 handlers_.push_back(source); 443 444 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser( 445 source, mime_type, get_attached_images); 446 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser))); 447 } 448 #endif // !defined(OS_ANDROID) && !defined(OS_IOS) 449 450 #if defined(OS_WIN) 451 void ChromeContentUtilityClient::OnParseITunesPrefXml( 452 const std::string& itunes_xml_data) { 453 base::FilePath library_path( 454 itunes::FindLibraryLocationInPrefXml(itunes_xml_data)); 455 Send(new ChromeUtilityHostMsg_GotITunesDirectory(library_path)); 456 ReleaseProcessIfNeeded(); 457 } 458 #endif // defined(OS_WIN) 459 460 #if defined(OS_MACOSX) 461 void ChromeContentUtilityClient::OnParseIPhotoLibraryXmlFile( 462 const IPC::PlatformFileForTransit& iphoto_library_file) { 463 iphoto::IPhotoLibraryParser parser; 464 base::File file = IPC::PlatformFileForTransitToFile(iphoto_library_file); 465 bool result = parser.Parse(iapps::ReadFileAsString(file.Pass())); 466 Send(new ChromeUtilityHostMsg_GotIPhotoLibrary(result, parser.library())); 467 ReleaseProcessIfNeeded(); 468 } 469 #endif // defined(OS_MACOSX) 470 471 #if defined(OS_WIN) || defined(OS_MACOSX) 472 void ChromeContentUtilityClient::OnParseITunesLibraryXmlFile( 473 const IPC::PlatformFileForTransit& itunes_library_file) { 474 itunes::ITunesLibraryParser parser; 475 base::File file = IPC::PlatformFileForTransitToFile(itunes_library_file); 476 bool result = parser.Parse(iapps::ReadFileAsString(file.Pass())); 477 Send(new ChromeUtilityHostMsg_GotITunesLibrary(result, parser.library())); 478 ReleaseProcessIfNeeded(); 479 } 480 481 void ChromeContentUtilityClient::OnParsePicasaPMPDatabase( 482 const picasa::AlbumTableFilesForTransit& album_table_files) { 483 picasa::AlbumTableFiles files; 484 files.indicator_file = 485 IPC::PlatformFileForTransitToFile(album_table_files.indicator_file); 486 files.category_file = 487 IPC::PlatformFileForTransitToFile(album_table_files.category_file); 488 files.date_file = 489 IPC::PlatformFileForTransitToFile(album_table_files.date_file); 490 files.filename_file = 491 IPC::PlatformFileForTransitToFile(album_table_files.filename_file); 492 files.name_file = 493 IPC::PlatformFileForTransitToFile(album_table_files.name_file); 494 files.token_file = 495 IPC::PlatformFileForTransitToFile(album_table_files.token_file); 496 files.uid_file = 497 IPC::PlatformFileForTransitToFile(album_table_files.uid_file); 498 499 picasa::PicasaAlbumTableReader reader(files.Pass()); 500 bool parse_success = reader.Init(); 501 Send(new ChromeUtilityHostMsg_ParsePicasaPMPDatabase_Finished( 502 parse_success, 503 reader.albums(), 504 reader.folders())); 505 ReleaseProcessIfNeeded(); 506 } 507 508 void ChromeContentUtilityClient::OnIndexPicasaAlbumsContents( 509 const picasa::AlbumUIDSet& album_uids, 510 const std::vector<picasa::FolderINIContents>& folders_inis) { 511 picasa::PicasaAlbumsIndexer indexer(album_uids); 512 indexer.ParseFolderINI(folders_inis); 513 514 Send(new ChromeUtilityHostMsg_IndexPicasaAlbumsContents_Finished( 515 indexer.albums_images())); 516 ReleaseProcessIfNeeded(); 517 } 518 #endif // defined(OS_WIN) || defined(OS_MACOSX) 519 520 #if defined(OS_WIN) 521 void ChromeContentUtilityClient::OnGetAndEncryptWiFiCredentials( 522 const std::string& network_guid, 523 const std::vector<uint8>& public_key) { 524 scoped_ptr<wifi::WiFiService> wifi_service(wifi::WiFiService::Create()); 525 wifi_service->Initialize(NULL); 526 527 std::string key_data; 528 std::string error; 529 wifi_service->GetKeyFromSystem(network_guid, &key_data, &error); 530 531 std::vector<uint8> ciphertext; 532 bool success = error.empty() && !key_data.empty(); 533 if (success) { 534 NetworkingPrivateCrypto crypto; 535 success = crypto.EncryptByteString(public_key, key_data, &ciphertext); 536 } 537 538 Send(new ChromeUtilityHostMsg_GotEncryptedWiFiCredentials(ciphertext, 539 success)); 540 } 541 #endif // defined(OS_WIN) 542