12fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// Copyright (C) 2013 Google Inc. 22fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 32fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// Licensed under the Apache License, Version 2.0 (the "License"); 42fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// you may not use this file except in compliance with the License. 52fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// You may obtain a copy of the License at 62fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 72fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// http://www.apache.org/licenses/LICENSE-2.0 82fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 92fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// Unless required by applicable law or agreed to in writing, software 102fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// distributed under the License is distributed on an "AS IS" BASIS, 112fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 122fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// See the License for the specific language governing permissions and 132fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// limitations under the License. 142fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 152fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// ValidatingUtil wraps data with checksum and timestamp. Format: 162fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 172fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// timestamp=<timestamp> 182fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// checksum=<checksum> 192fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// <data> 202fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 212fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// The timestamp is the time_t that was returned from time() function. The 222fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// timestamp does not need to be portable because it is written and read only by 232fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// ValidatingUtil. The value is somewhat human-readable: it is the number of 242fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// seconds since the epoch. 252fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// 262fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// The checksum is the 32-character hexadecimal MD5 checksum of <data>. It is 272fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// meant to protect from random file changes on disk. 282fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 292fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include "validating_util.h" 302fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 312fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <cassert> 322fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <cstddef> 332fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <cstdio> 342fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <cstdlib> 352fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <ctime> 362fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include <string> 372fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 382fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org#include "util/md5.h" 392fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 402fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgnamespace i18n { 412fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgnamespace addressinput { 422fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 432fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgnamespace { 442fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 452fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgconst char kTimestampPrefix[] = "timestamp="; 462fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgconst size_t kTimestampPrefixLength = sizeof kTimestampPrefix - 1; 472fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 482fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgconst char kChecksumPrefix[] = "checksum="; 492fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgconst size_t kChecksumPrefixLength = sizeof kChecksumPrefix - 1; 502fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 512fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgconst char kSeparator = '\n'; 522fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 532fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// Places the header value into |header_value| parameter and erases the header 542fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// from |data|. Returns |true| if the header format is valid. 552fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgbool UnwrapHeader(const char* header_prefix, 562fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org size_t header_prefix_length, 572fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org std::string* data, 582fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org std::string* header_value) { 592fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org assert(header_prefix != NULL); 602fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org assert(data != NULL); 612fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org assert(header_value != NULL); 622fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 632fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (data->compare( 642fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 0, header_prefix_length, header_prefix, header_prefix_length) != 0) { 652fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 662fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 672fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 682fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org std::string::size_type separator_position = 692fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org data->find(kSeparator, header_prefix_length); 702fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (separator_position == std::string::npos) { 712fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 722fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 732fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 742fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org header_value->assign( 752fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org *data, header_prefix_length, separator_position - header_prefix_length); 762fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org data->erase(0, separator_position + 1); 772fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 782fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return true; 792fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} 802fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 812fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} // namespace 822fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 832fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// static 84128ae075bbf50996c1068740746f27430f89136droubert@google.comvoid ValidatingUtil::Wrap(time_t timestamp, std::string* data) { 85128ae075bbf50996c1068740746f27430f89136droubert@google.com assert(data != NULL); 862fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org char timestamp_string[2 + 3 * sizeof timestamp]; 87945d96387a716d0d82b195fa69a5e9a701249517rouslan@chromium.org int size = 88945d96387a716d0d82b195fa69a5e9a701249517rouslan@chromium.org std::sprintf(timestamp_string, "%ld", static_cast<long>(timestamp)); 898a5ea9e2e8b5642281fa679b70266b80a4bf039drouslan@chromium.org assert(size > 0); 908a5ea9e2e8b5642281fa679b70266b80a4bf039drouslan@chromium.org assert(size < sizeof timestamp_string); 918a5ea9e2e8b5642281fa679b70266b80a4bf039drouslan@chromium.org (void)size; 922fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 93128ae075bbf50996c1068740746f27430f89136droubert@google.com std::string header; 94128ae075bbf50996c1068740746f27430f89136droubert@google.com header.append(kTimestampPrefix, kTimestampPrefixLength); 95128ae075bbf50996c1068740746f27430f89136droubert@google.com header.append(timestamp_string); 96128ae075bbf50996c1068740746f27430f89136droubert@google.com header.push_back(kSeparator); 972fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 98128ae075bbf50996c1068740746f27430f89136droubert@google.com header.append(kChecksumPrefix, kChecksumPrefixLength); 99128ae075bbf50996c1068740746f27430f89136droubert@google.com header.append(MD5String(*data)); 100128ae075bbf50996c1068740746f27430f89136droubert@google.com header.push_back(kSeparator); 1012fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 102128ae075bbf50996c1068740746f27430f89136droubert@google.com data->reserve(header.size() + data->size()); 103128ae075bbf50996c1068740746f27430f89136droubert@google.com data->insert(0, header); 1042fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} 1052fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1062fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// static 1072fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgbool ValidatingUtil::UnwrapTimestamp(std::string* data, time_t now) { 1082fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org assert(data != NULL); 1092fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (now < 0) { 1102fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 1112fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 1122fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1132fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org std::string timestamp_string; 1142fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (!UnwrapHeader( 115000aa6dbb70273ccefa77a5d4cd1a400939a2666roubert@google.com kTimestampPrefix, kTimestampPrefixLength, data, ×tamp_string)) { 1162fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 1172fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 1182fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1192fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org time_t timestamp = atol(timestamp_string.c_str()); 1202fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (timestamp < 0) { 1212fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 1222fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 1232fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1242fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org // One month contains: 1252fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org // 30 days * 1262fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org // 24 hours per day * 1272fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org // 60 minutes per hour * 1282fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org // 60 seconds per minute. 1292fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org static const double kOneMonthInSeconds = 30.0 * 24.0 * 60.0 * 60.0; 1302fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org double age_in_seconds = difftime(now, timestamp); 1312fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return !(age_in_seconds < 0.0) && age_in_seconds < kOneMonthInSeconds; 1322fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} 1332fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1342fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org// static 1352fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.orgbool ValidatingUtil::UnwrapChecksum(std::string* data) { 1362fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org assert(data != NULL); 1372fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org std::string checksum; 1382fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org if (!UnwrapHeader(kChecksumPrefix, kChecksumPrefixLength, data, &checksum)) { 1392fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return false; 1402fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org } 1412fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org return checksum == MD5String(*data); 1422fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} 1432fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org 1442fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} // namespace addressinput 1452fefd83dd2c65ee585a2aa05e4856eb4d0e93f0brouslan@chromium.org} // namespace i18n 146