tdlight/td/telegram/files/FileEncryptionKey.h
levlam 4c5c2422d3 Add FileEncryptionKey.h.
GitOrigin-RevId: e21c5ae48403835fb910e55545b64d6edf4f6651
2018-12-27 21:06:21 +03:00

156 lines
4.3 KiB
C++

//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/SecureStorage.h"
#include "td/utils/as.h"
#include "td/utils/common.h"
#include "td/utils/crypto.h"
#include "td/utils/logging.h"
#include "td/utils/Random.h"
#include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
#include "td/utils/UInt.h"
namespace td {
struct FileEncryptionKey {
enum class Type : int32 { None, Secret, Secure };
FileEncryptionKey() = default;
FileEncryptionKey(Slice key, Slice iv) : key_iv_(key.size() + iv.size(), '\0'), type_(Type::Secret) {
if (key.size() != 32 || iv.size() != 32) {
LOG(ERROR) << "Wrong key/iv sizes: " << key.size() << " " << iv.size();
type_ = Type::None;
return;
}
CHECK(key_iv_.size() == 64);
MutableSlice(key_iv_).copy_from(key);
MutableSlice(key_iv_).substr(key.size()).copy_from(iv);
}
explicit FileEncryptionKey(const secure_storage::Secret &secret) : type_(Type::Secure) {
key_iv_ = secret.as_slice().str();
}
bool is_secret() const {
return type_ == Type::Secret;
}
bool is_secure() const {
return type_ == Type::Secure;
}
static FileEncryptionKey create() {
FileEncryptionKey res;
res.key_iv_.resize(64);
Random::secure_bytes(res.key_iv_);
res.type_ = Type::Secret;
return res;
}
static FileEncryptionKey create_secure_key() {
return FileEncryptionKey(secure_storage::Secret::create_new());
}
const UInt256 &key() const {
CHECK(is_secret());
CHECK(key_iv_.size() == 64);
return *reinterpret_cast<const UInt256 *>(key_iv_.data());
}
Slice key_slice() const {
CHECK(is_secret());
CHECK(key_iv_.size() == 64);
return Slice(key_iv_.data(), 32);
}
secure_storage::Secret secret() const {
CHECK(is_secure());
return secure_storage::Secret::create(Slice(key_iv_).truncate(32)).move_as_ok();
}
bool has_value_hash() const {
CHECK(is_secure());
return key_iv_.size() > secure_storage::Secret::size();
}
void set_value_hash(const secure_storage::ValueHash &value_hash) {
key_iv_.resize(secure_storage::Secret::size() + value_hash.as_slice().size());
MutableSlice(key_iv_).remove_prefix(secure_storage::Secret::size()).copy_from(value_hash.as_slice());
}
secure_storage::ValueHash value_hash() const {
CHECK(has_value_hash());
return secure_storage::ValueHash::create(Slice(key_iv_).remove_prefix(secure_storage::Secret::size())).move_as_ok();
}
UInt256 &mutable_iv() {
CHECK(is_secret());
CHECK(key_iv_.size() == 64);
return *reinterpret_cast<UInt256 *>(&key_iv_[0] + 32);
}
Slice iv_slice() const {
CHECK(is_secret());
CHECK(key_iv_.size() == 64);
return Slice(key_iv_.data() + 32, 32);
}
int32 calc_fingerprint() const {
CHECK(is_secret());
char buf[16];
md5(key_iv_, {buf, sizeof(buf)});
return as<int32>(buf) ^ as<int32>(buf + 4);
}
bool empty() const {
return key_iv_.empty();
}
size_t size() const {
return key_iv_.size();
}
template <class StorerT>
void store(StorerT &storer) const {
td::store(key_iv_, storer);
}
template <class ParserT>
void parse(Type type, ParserT &parser) {
td::parse(key_iv_, parser);
if (key_iv_.empty()) {
type_ = Type::None;
} else {
if (type_ == Type::Secure) {
if (key_iv_.size() != 64) {
LOG(ERROR) << "Have wrong key size " << key_iv_.size();
}
}
type_ = type;
}
}
string key_iv_; // TODO wrong alignment is possible
Type type_ = Type::None;
};
inline bool operator==(const FileEncryptionKey &lhs, const FileEncryptionKey &rhs) {
return lhs.key_iv_ == rhs.key_iv_;
}
inline bool operator!=(const FileEncryptionKey &lhs, const FileEncryptionKey &rhs) {
return !(lhs == rhs);
}
inline StringBuilder &operator<<(StringBuilder &string_builder, const FileEncryptionKey &key) {
if (key.is_secret()) {
return string_builder << "SecretKey{" << key.size() << "}";
}
if (key.is_secret()) {
return string_builder << "SecureKey{" << key.size() << "}";
}
return string_builder << "NoKey{}";
}
} // namespace td