Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 | /** |
| 3 | * Copyright (c) 2013-2016, Regents of the University of California. |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 4 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 5 | * This file is part of ChronoShare, a decentralized file sharing application over NDN. |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 6 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 7 | * ChronoShare is free software: you can redistribute it and/or modify it under the terms |
| 8 | * of the GNU General Public License as published by the Free Software Foundation, either |
| 9 | * version 3 of the License, or (at your option) any later version. |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 10 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 11 | * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY |
| 12 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
| 13 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 14 | * |
Alexander Afanasyev | fa2f662 | 2016-12-25 12:28:00 -0800 | [diff] [blame] | 15 | * You should have received copies of the GNU General Public License along with |
| 16 | * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>. |
| 17 | * |
| 18 | * See AUTHORS.md for complete list of ChronoShare authors and contributors. |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 19 | */ |
| 20 | |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 21 | #include "hash-helper.h" |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 22 | |
| 23 | #include <boost/assert.hpp> |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 24 | #include <boost/lexical_cast.hpp> |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 25 | #include <boost/make_shared.hpp> |
| 26 | #include <boost/throw_exception.hpp> |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 27 | #include <fstream> |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 28 | #include <openssl/evp.h> |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 29 | |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 30 | typedef boost::error_info<struct tag_errmsg, std::string> errmsg_info_str; |
| 31 | typedef boost::error_info<struct tag_errmsg, int> errmsg_info_int; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 32 | |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 33 | #include <boost/archive/iterators/dataflow_exception.hpp> |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 34 | #include <boost/archive/iterators/transform_width.hpp> |
Alexander Afanasyev | 68f2a95 | 2013-01-08 14:34:16 -0800 | [diff] [blame] | 35 | #include <boost/filesystem/fstream.hpp> |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 36 | #include <boost/iterator/transform_iterator.hpp> |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 37 | |
| 38 | using namespace boost; |
| 39 | using namespace boost::archive::iterators; |
| 40 | using namespace std; |
Alexander Afanasyev | 68f2a95 | 2013-01-08 14:34:16 -0800 | [diff] [blame] | 41 | namespace fs = boost::filesystem; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 42 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 43 | template <class CharType> |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 44 | struct hex_from_4_bit |
| 45 | { |
| 46 | typedef CharType result_type; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 47 | CharType |
| 48 | operator()(CharType ch) const |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 49 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 50 | const char* lookup_table = "0123456789abcdef"; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 51 | // cout << "New character: " << (int) ch << " (" << (char) ch << ")" << "\n"; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 52 | BOOST_ASSERT(ch < 16); |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 53 | return lookup_table[static_cast<size_t>(ch)]; |
| 54 | } |
| 55 | }; |
| 56 | |
| 57 | typedef transform_iterator<hex_from_4_bit<string::const_iterator::value_type>, |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 58 | transform_width<string::const_iterator, 4, 8, string::const_iterator::value_type>> |
| 59 | string_from_binary; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 60 | |
| 61 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 62 | template <class CharType> |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 63 | struct hex_to_4_bit |
| 64 | { |
| 65 | typedef CharType result_type; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 66 | CharType |
| 67 | operator()(CharType ch) const |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 68 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 69 | const signed char lookup_table[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 70 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 71 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 72 | -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, |
| 73 | -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, |
| 74 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 75 | -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, |
| 76 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| 77 | -1, -1, -1, -1, -1, -1, -1, -1}; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 78 | |
| 79 | // cout << "New character: " << hex << (int) ch << " (" << (char) ch << ")" << "\n"; |
| 80 | signed char value = -1; |
| 81 | if ((unsigned)ch < 128) |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 82 | value = lookup_table[(unsigned)ch]; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 83 | if (value == -1) |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 84 | BOOST_THROW_EXCEPTION(Error::HashConversion() << errmsg_info_int((int)ch)); |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 85 | |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 86 | return value; |
| 87 | } |
| 88 | }; |
| 89 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 90 | typedef transform_width< |
| 91 | transform_iterator<hex_to_4_bit<string::const_iterator::value_type>, string::const_iterator>, |
| 92 | 8, |
| 93 | 4> |
| 94 | string_to_binary; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 95 | |
| 96 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 97 | std::ostream& |
| 98 | operator<<(std::ostream& os, const Hash& hash) |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 99 | { |
| 100 | if (hash.m_length == 0) |
| 101 | return os; |
| 102 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 103 | ostreambuf_iterator<char> out_it(os); // ostream iterator |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 104 | // need to encode to base64 |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 105 | copy(string_from_binary(reinterpret_cast<const char*>(hash.m_buf)), |
| 106 | string_from_binary(reinterpret_cast<const char*>(hash.m_buf + hash.m_length)), |
| 107 | out_it); |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 108 | |
| 109 | return os; |
| 110 | } |
| 111 | |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 112 | std::string |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 113 | Hash::shortHash() const |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 114 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 115 | return lexical_cast<string>(*this).substr(0, 10); |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | |
Zhenkai Zhu | e851b95 | 2013-01-13 22:29:57 -0800 | [diff] [blame] | 119 | unsigned char Hash::_origin = 0; |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 120 | HashPtr |
| 121 | Hash::Origin(new Hash(&Hash::_origin, sizeof(unsigned char))); |
Zhenkai Zhu | e851b95 | 2013-01-13 22:29:57 -0800 | [diff] [blame] | 122 | |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 123 | HashPtr |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 124 | Hash::FromString(const std::string& hashInTextEncoding) |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 125 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 126 | HashPtr retval = make_shared<Hash>(reinterpret_cast<void*>(0), 0); |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 127 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 128 | if (hashInTextEncoding.size() == 0) { |
| 129 | return retval; |
| 130 | } |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 131 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 132 | if (hashInTextEncoding.size() > EVP_MAX_MD_SIZE * 2) { |
| 133 | cerr << "Input hash is too long. Returning an empty hash" << endl; |
| 134 | return retval; |
| 135 | } |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 136 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 137 | retval->m_buf = new unsigned char[EVP_MAX_MD_SIZE]; |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 138 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 139 | unsigned char* end = copy(string_to_binary(hashInTextEncoding.begin()), |
| 140 | string_to_binary(hashInTextEncoding.end()), |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 141 | retval->m_buf); |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 142 | |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 143 | retval->m_length = end - retval->m_buf; |
| 144 | |
| 145 | return retval; |
Alexander Afanasyev | de1cdd0 | 2012-12-29 14:41:46 -0800 | [diff] [blame] | 146 | } |
| 147 | |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 148 | HashPtr |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 149 | Hash::FromFileContent(const fs::path& filename) |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 150 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 151 | HashPtr retval = make_shared<Hash>(reinterpret_cast<void*>(0), 0); |
| 152 | retval->m_buf = new unsigned char[EVP_MAX_MD_SIZE]; |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 153 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 154 | EVP_MD_CTX* hash_context = EVP_MD_CTX_create(); |
| 155 | EVP_DigestInit_ex(hash_context, HASH_FUNCTION(), 0); |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 156 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 157 | fs::ifstream iff(filename, std::ios::in | std::ios::binary); |
| 158 | while (iff.good()) { |
| 159 | char buf[1024]; |
| 160 | iff.read(buf, 1024); |
| 161 | EVP_DigestUpdate(hash_context, buf, iff.gcount()); |
| 162 | } |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 163 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 164 | retval->m_buf = new unsigned char[EVP_MAX_MD_SIZE]; |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 165 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 166 | EVP_DigestFinal_ex(hash_context, retval->m_buf, &retval->m_length); |
Alexander Afanasyev | fcf81dc | 2013-01-25 20:36:58 -0800 | [diff] [blame] | 167 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 168 | EVP_MD_CTX_destroy(hash_context); |
Alexander Afanasyev | a199f97 | 2013-01-02 19:37:26 -0800 | [diff] [blame] | 169 | |
| 170 | return retval; |
| 171 | } |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 172 | |
| 173 | HashPtr |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 174 | Hash::FromBytes(const Ccnx::Bytes& bytes) |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 175 | { |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 176 | HashPtr retval = make_shared<Hash>(reinterpret_cast<void*>(0), 0); |
| 177 | retval->m_buf = new unsigned char[EVP_MAX_MD_SIZE]; |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 178 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 179 | EVP_MD_CTX* hash_context = EVP_MD_CTX_create(); |
| 180 | EVP_DigestInit_ex(hash_context, HASH_FUNCTION(), 0); |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 181 | |
| 182 | // not sure whether it's bad to do so if bytes.size is huge |
Alexander Afanasyev | 1dd37ed | 2013-08-14 18:08:09 -0700 | [diff] [blame] | 183 | EVP_DigestUpdate(hash_context, Ndnx::head(bytes), bytes.size()); |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 184 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 185 | retval->m_buf = new unsigned char[EVP_MAX_MD_SIZE]; |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 186 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 187 | EVP_DigestFinal_ex(hash_context, retval->m_buf, &retval->m_length); |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 188 | |
Alexander Afanasyev | eda3b7a | 2016-12-25 11:26:40 -0800 | [diff] [blame^] | 189 | EVP_MD_CTX_destroy(hash_context); |
Zhenkai Zhu | 9dd9adc | 2013-03-13 16:12:09 -0700 | [diff] [blame] | 190 | |
| 191 | return retval; |
| 192 | } |