diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h
index 235690160..8a4ad1e43 100644
--- a/Telegram/SourceFiles/config.h
+++ b/Telegram/SourceFiles/config.h
@@ -76,7 +76,6 @@ enum {
 	LocalEncryptIterCount = 4000, // key derivation iteration count
 	LocalEncryptNoPwdIterCount = 4, // key derivation iteration count without pwd (not secure anyway)
 	LocalEncryptSaltSize = 32, // 256 bit
-	LocalEncryptKeySize = 256, // 2048 bit
 
 	AnimationTimerDelta = 7,
 	ClipThreadsCount = 8,
diff --git a/Telegram/SourceFiles/core/utils.h b/Telegram/SourceFiles/core/utils.h
index ce97b7c3a..3e63aba87 100644
--- a/Telegram/SourceFiles/core/utils.h
+++ b/Telegram/SourceFiles/core/utils.h
@@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #pragma once
 
 #include "core/basic_types.h"
+#include <array>
 
 namespace base {
 
@@ -242,13 +243,37 @@ private:
 };
 
 int32 hashCrc32(const void *data, uint32 len);
+
 int32 *hashSha1(const void *data, uint32 len, void *dest); // dest - ptr to 20 bytes, returns (int32*)dest
+inline std::array<char, 20> hashSha1(const void *data, int len) {
+	auto result = std::array<char, 20>();
+	hashSha1(data, len, result.data());
+	return result;
+}
+
 int32 *hashSha256(const void *data, uint32 len, void *dest); // dest - ptr to 32 bytes, returns (int32*)dest
+inline std::array<char, 32> hashSha256(const void *data, int size) {
+	auto result = std::array<char, 32>();
+	hashSha1(data, size, result.data());
+	return result;
+}
+
 int32 *hashMd5(const void *data, uint32 len, void *dest); // dest = ptr to 16 bytes, returns (int32*)dest
+inline std::array<char, 16> hashMd5(const void *data, int size) {
+	auto result = std::array<char, 16>();
+	hashMd5(data, size, result.data());
+	return result;
+}
+
 char *hashMd5Hex(const int32 *hashmd5, void *dest); // dest = ptr to 32 bytes, returns (char*)dest
 inline char *hashMd5Hex(const void *data, uint32 len, void *dest) { // dest = ptr to 32 bytes, returns (char*)dest
 	return hashMd5Hex(HashMd5(data, len).result(), dest);
 }
+inline std::array<char, 32> hashMd5Hex(const void *data, int size) {
+	auto result = std::array<char, 32>();
+	hashMd5Hex(data, size, result.data());
+	return result;
+}
 
 // good random (using openssl implementation)
 void memset_rand(void *data, uint32 len);
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index 5b21808a0..cbcf62a74 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -135,9 +135,10 @@ bool _checkStreamStatus(QDataStream &stream) {
 
 QByteArray _settingsSalt, _passKeySalt, _passKeyEncrypted;
 
+constexpr auto kLocalKeySize = MTP::AuthKey::kSize;
 MTP::AuthKey _oldKey, _settingsKey, _passKey, _localKey;
 void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKey *result) {
-	uchar key[LocalEncryptKeySize] = { 0 };
+	MTP::AuthKey::Data key = { 0 };
 	int32 iterCount = pass.size() ? LocalEncryptIterCount : LocalEncryptNoPwdIterCount; // dont slow down for no password
 	QByteArray newSalt;
 	if (!salt) {
@@ -148,7 +149,7 @@ void createLocalKey(const QByteArray &pass, QByteArray *salt, MTP::AuthKey *resu
 		cSetLocalSalt(newSalt);
 	}
 
-	PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, LocalEncryptKeySize, key);
+	PKCS5_PBKDF2_HMAC_SHA1(pass.constData(), pass.size(), (uchar*)salt->data(), salt->size(), iterCount, key.size(), (uchar*)key.data());
 
 	result->setKey(key);
 }
@@ -894,18 +895,12 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version) {
 
 	case dbiKey: {
 		qint32 dcId;
-		quint32 key[64];
+		MTP::AuthKey::Data key = { 0 };
 		stream >> dcId;
-		stream.readRawData((char*)key, 256);
+		stream.readRawData(key.data(), key.size());
 		if (!_checkStreamStatus(stream)) return false;
 
-		DEBUG_LOG(("MTP Info: key found, dc %1, key: %2").arg(dcId).arg(Logs::mb(key, 256).str()));
-		dcId = MTP::bareDcId(dcId);
-		MTP::AuthKeyPtr keyPtr(new MTP::AuthKey());
-		keyPtr->setKey(key);
-		keyPtr->setDC(dcId);
-
-		MTP::setKey(dcId, keyPtr);
+		MTP::setKey(dcId, key);
 	} break;
 
 	case dbiAutoStart: {
@@ -1777,14 +1772,14 @@ void _writeMtpData() {
 		return;
 	}
 
-	MTP::AuthKeysMap keys = MTP::getKeys();
+	auto keys = MTP::getKeys();
 
 	quint32 size = sizeof(quint32) + sizeof(qint32) + sizeof(quint32);
-	size += keys.size() * (sizeof(quint32) + sizeof(quint32) + 256);
+	size += keys.size() * (sizeof(quint32) + sizeof(quint32) + MTP::AuthKey::kSize);
 
 	EncryptedDescriptor data(size);
 	data.stream << quint32(dbiUser) << qint32(MTP::authedId()) << quint32(MTP::maindc());
-	for_const (const MTP::AuthKeyPtr &key, keys) {
+	for_const (auto &key, keys) {
 		data.stream << quint32(dbiKey) << quint32(key->getDC());
 		key->write(data.stream);
 	}
@@ -1847,8 +1842,8 @@ ReadMapState _readMap(const QByteArray &pass) {
 		LOG(("App Info: could not decrypt pass-protected key from map file, maybe bad password..."));
 		return ReadMapPassNeeded;
 	}
-	uchar key[LocalEncryptKeySize] = { 0 };
-	if (keyData.stream.readRawData((char*)key, LocalEncryptKeySize) != LocalEncryptKeySize || !keyData.stream.atEnd()) {
+	auto key = MTP::AuthKey::Data { 0 };
+	if (keyData.stream.readRawData(key.data(), key.size()) != key.size() || !keyData.stream.atEnd()) {
 		LOG(("App Error: could not read pass-protected key from map file"));
 		return ReadMapFailed;
 	}
@@ -2044,8 +2039,7 @@ void _writeMap(WriteMapWhen when) {
 
 	FileWriteDescriptor map(qsl("map"));
 	if (_passKeySalt.isEmpty() || _passKeyEncrypted.isEmpty()) {
-		uchar local5Key[LocalEncryptKeySize] = { 0 };
-		QByteArray pass(LocalEncryptKeySize, Qt::Uninitialized), salt(LocalEncryptSaltSize, Qt::Uninitialized);
+		QByteArray pass(kLocalKeySize, Qt::Uninitialized), salt(LocalEncryptSaltSize, Qt::Uninitialized);
 		memset_rand(pass.data(), pass.size());
 		memset_rand(salt.data(), salt.size());
 		createLocalKey(pass, &salt, &_localKey);
@@ -2054,7 +2048,7 @@ void _writeMap(WriteMapWhen when) {
 		memset_rand(_passKeySalt.data(), _passKeySalt.size());
 		createLocalKey(QByteArray(), &_passKeySalt, &_passKey);
 
-		EncryptedDescriptor passKeyData(LocalEncryptKeySize);
+		EncryptedDescriptor passKeyData(kLocalKeySize);
 		_localKey.write(passKeyData.stream);
 		_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, _passKey);
 	}
@@ -2376,15 +2370,15 @@ void reset() {
 }
 
 bool checkPasscode(const QByteArray &passcode) {
-	MTP::AuthKey tmp;
-	createLocalKey(passcode, &_passKeySalt, &tmp);
-	return (tmp == _passKey);
+	auto checkKey = MTP::AuthKey();
+	createLocalKey(passcode, &_passKeySalt, &checkKey);
+	return (checkKey == _passKey);
 }
 
 void setPasscode(const QByteArray &passcode) {
 	createLocalKey(passcode, &_passKeySalt, &_passKey);
 
-	EncryptedDescriptor passKeyData(LocalEncryptKeySize);
+	EncryptedDescriptor passKeyData(kLocalKeySize);
 	_localKey.write(passKeyData.stream);
 	_passKeyEncrypted = FileWriteDescriptor::prepareEncrypted(passKeyData, _passKey);
 
diff --git a/Telegram/SourceFiles/mtproto/auth_key.h b/Telegram/SourceFiles/mtproto/auth_key.h
index 963940d1a..22860c14d 100644
--- a/Telegram/SourceFiles/mtproto/auth_key.h
+++ b/Telegram/SourceFiles/mtproto/auth_key.h
@@ -20,30 +20,34 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 */
 #pragma once
 
+#include <array>
+#include <memory>
+
 namespace MTP {
 
 class AuthKey {
 public:
-
-	AuthKey() : _isset(false), _dc(0) {
-	}
+	static constexpr auto kSize = 256; // 2048 bits.
+	using Data = std::array<char, kSize>;
 
 	bool created() const {
 		return _isset;
 	}
 
-	void setKey(const void *from) {
-		memcpy(_key, from, 256);
-		uchar sha1Buffer[20];
-		_keyId = *(uint64*)(hashSha1(_key, 256, sha1Buffer) + 3);
+	void setKey(const Data &from) {
+		_key = from;
+		auto sha1 = hashSha1(_key.data(), _key.size());
+
+		// Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
+		_keyId = *reinterpret_cast<uint64*>(sha1.data() + 12);
 		_isset = true;
 	}
 
-	void setDC(uint32 dc) {
+	void setDC(int dc) {
 		_dc = dc;
 	}
 
-	uint32 getDC() const {
+	int getDC() const {
 		t_assert(_isset);
 		return _dc;
 	}
@@ -60,26 +64,27 @@ public:
 
 		uchar data_a[16 + 32], sha1_a[20];
 		memcpy(data_a, &msgKey, 16);
-		memcpy(data_a + 16, _key + x, 32);
+		memcpy(data_a + 16, _key.data() + x, 32);
 		hashSha1(data_a, 16 + 32, sha1_a);
 
 		uchar data_b[16 + 16 + 16], sha1_b[20];
-		memcpy(data_b, _key + 32 + x, 16);
+		memcpy(data_b, _key.data() + 32 + x, 16);
 		memcpy(data_b + 16, &msgKey, 16);
-		memcpy(data_b + 32, _key + 48 + x, 16);
+		memcpy(data_b + 32, _key.data() + 48 + x, 16);
 		hashSha1(data_b, 16 + 16 + 16, sha1_b);
 
 		uchar data_c[32 + 16], sha1_c[20];
-		memcpy(data_c, _key + 64 + x, 32);
+		memcpy(data_c, _key.data() + 64 + x, 32);
 		memcpy(data_c + 32, &msgKey, 16);
 		hashSha1(data_c, 32 + 16, sha1_c);
 
 		uchar data_d[16 + 32], sha1_d[20];
 		memcpy(data_d, &msgKey, 16);
-		memcpy(data_d + 16, _key + 96 + x, 32);
+		memcpy(data_d + 16, _key.data() + 96 + x, 32);
 		hashSha1(data_d, 16 + 32, sha1_d);
 
-		uchar *key((uchar*)&aesKey), *iv((uchar*)&aesIV);
+		auto key = reinterpret_cast<uchar*>(&aesKey);
+		auto iv = reinterpret_cast<uchar*>(&aesIV);
 		memcpy(key, sha1_a, 8);
 		memcpy(key + 8, sha1_b + 8, 12);
 		memcpy(key + 8 + 12, sha1_c + 4, 12);
@@ -91,7 +96,7 @@ public:
 
 	void write(QDataStream &to) const {
 		t_assert(_isset);
-		to.writeRawData(_key, 256);
+		to.writeRawData(_key.data(), _key.size());
 	}
 
 	static const uint64 RecreateKeyId = 0xFFFFFFFFFFFFFFFFL;
@@ -99,20 +104,19 @@ public:
 	friend bool operator==(const AuthKey &a, const AuthKey &b);
 
 private:
-
-	char _key[256];
-	uint64 _keyId;
-	bool _isset;
-	uint32 _dc;
+	Data _key = { 0 };
+	uint64 _keyId = 0;
+	bool _isset = false;
+	int _dc = 0;
 
 };
 
 inline bool operator==(const AuthKey &a, const AuthKey &b) {
-	return !memcmp(a._key, b._key, 256);
+	return (a._key == b._key);
 }
 
-typedef QSharedPointer<AuthKey> AuthKeyPtr;
-typedef QVector<AuthKeyPtr> AuthKeysMap;
+using AuthKeyPtr = std::shared_ptr<AuthKey>;
+using AuthKeysMap = QVector<AuthKeyPtr>;
 
 void aesIgeEncrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
 void aesIgeDecrypt(const void *src, void *dst, uint32 len, const void *key, const void *iv);
diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp
index 5d91fc6f5..cf67febb1 100644
--- a/Telegram/SourceFiles/mtproto/connection.cpp
+++ b/Telegram/SourceFiles/mtproto/connection.cpp
@@ -443,7 +443,7 @@ ConnectionPrivate::ConnectionPrivate(QThread *thread, Connection *owner, Session
 , _owner(owner)
 , _waitForReceived(MTPMinReceiveDelay)
 , _waitForConnected(MTPMinConnectDelay)
-//	, sessionDataMutex(QReadWriteLock::Recursive)
+//, sessionDataMutex(QReadWriteLock::Recursive)
 , sessionData(data) {
 	oldConnectionTimer.moveToThread(thread);
 	_waitForConnectedTimer.moveToThread(thread);
@@ -1197,7 +1197,7 @@ void ConnectionPrivate::restart(bool mayBeBadKey) {
 	_waitForReceivedTimer.stop();
 	_waitForConnectedTimer.stop();
 
-	AuthKeyPtr key(sessionData->getKey());
+	auto key = sessionData->getKey();
 	if (key) {
 		if (!sessionData->isCheckedKey()) {
 			if (mayBeBadKey) {
@@ -1368,7 +1368,7 @@ void ConnectionPrivate::handleReceived() {
 		return restart();
 	}
 
-	AuthKeyPtr key(sessionData->getKey());
+	auto key = sessionData->getKey();
 	if (!key || key->keyId() != keyId) {
 		DEBUG_LOG(("MTP Error: auth_key id for dc %1 changed").arg(dc));
 
@@ -2360,7 +2360,7 @@ void ConnectionPrivate::updateAuthKey() 	{
 			keyId = newKeyId;
 			return; // some other connection is getting key
 		}
-		const AuthKeyPtr &key(sessionData->getKey());
+		auto key = sessionData->getKey();
 		newKeyId = key ? key->keyId() : 0;
 	}
 	if (keyId != newKeyId) {
@@ -2642,15 +2642,14 @@ void ConnectionPrivate::dhClientParamsSend() {
 
 	// count g_b and auth_key using openssl BIGNUM methods
 	MTP::internal::BigNumCounter bnCounter;
-	if (!bnCounter.count(b, _authKeyStrings->dh_prime.constData(), _authKeyData->g, g_b, _authKeyStrings->g_a.constData(), _authKeyData->auth_key)) {
+	if (!bnCounter.count(b, _authKeyStrings->dh_prime.constData(), _authKeyData->g, g_b, _authKeyStrings->g_a.constData(), _authKeyStrings->auth_key.data())) {
 		return dhClientParamsSend();
 	}
 
 	// count auth_key hashes - parts of sha1(auth_key)
-	uchar sha1Buffer[20];
-	int32 *auth_key_sha = hashSha1(_authKeyData->auth_key, 256, sha1Buffer);
-	memcpy(&_authKeyData->auth_key_aux_hash, auth_key_sha, 8);
-	memcpy(&_authKeyData->auth_key_hash, auth_key_sha + 3, 8);
+	auto auth_key_sha = hashSha1(_authKeyStrings->auth_key.data(), _authKeyStrings->auth_key.size());
+	memcpy(&_authKeyData->auth_key_aux_hash, auth_key_sha.data(), 8);
+	memcpy(&_authKeyData->auth_key_hash, auth_key_sha.data() + 12, 8);
 
 	MTPSet_client_DH_params req_client_DH_params;
 	req_client_DH_params.vnonce = _authKeyData->nonce;
@@ -2727,11 +2726,11 @@ void ConnectionPrivate::dhClientParamsAnswered() {
 		uint64 salt1 = _authKeyData->new_nonce.l.l, salt2 = _authKeyData->server_nonce.l, serverSalt = salt1 ^ salt2;
 		sessionData->setSalt(serverSalt);
 
-		AuthKeyPtr authKey(new AuthKey());
-		authKey->setKey(_authKeyData->auth_key);
+		auto authKey = std::make_shared<AuthKey>();
+		authKey->setKey(_authKeyStrings->auth_key);
 		authKey->setDC(bareDcId(dc));
 
-		DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2, auth key: %3").arg(authKey->keyId()).arg(serverSalt).arg(Logs::mb(_authKeyData->auth_key, 256).str()));
+		DEBUG_LOG(("AuthKey Info: auth key gen succeed, id: %1, server salt: %2").arg(authKey->keyId()).arg(serverSalt));
 
 		sessionData->owner()->notifyKeyCreated(authKey); // slot will call authKeyCreated()
 		sessionData->clear();
@@ -2823,17 +2822,28 @@ void ConnectionPrivate::authKeyCreated() {
 }
 
 void ConnectionPrivate::clearAuthKeyData() {
-	if (_authKeyData) {
+	auto zeroMemory = [](void *data, int size) {
 #ifdef Q_OS_WIN
-		SecureZeroMemory(_authKeyData.get(), sizeof(AuthKeyCreateData));
-		if (!_authKeyStrings->dh_prime.isEmpty()) SecureZeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size());
-		if (!_authKeyStrings->g_a.isEmpty()) SecureZeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size());
-#else
-		memset(_authKeyData.get(), 0, sizeof(AuthKeyCreateData));
-		if (!_authKeyStrings->dh_prime.isEmpty()) memset(_authKeyStrings->dh_prime.data(), 0, _authKeyStrings->dh_prime.size());
-		if (!_authKeyStrings->g_a.isEmpty()) memset(_authKeyStrings->g_a.data(), 0, _authKeyStrings->g_a.size());
-#endif
+		SecureZeroMemory(data, size);
+#else // Q_OS_WIN
+		auto end = static_cast<char*>(data) + size;
+		for (volatile auto p = static_cast<volatile char*>(data); p != end; ++p) {
+			*p = 0;
+		}
+#endif // Q_OS_WIN
+	};
+	if (_authKeyData) {
+		zeroMemory(_authKeyData.get(), sizeof(AuthKeyCreateData));
 		_authKeyData.reset();
+	}
+	if (_authKeyStrings) {
+		if (!_authKeyStrings->dh_prime.isEmpty()) {
+			zeroMemory(_authKeyStrings->dh_prime.data(), _authKeyStrings->dh_prime.size());
+		}
+		if (!_authKeyStrings->g_a.isEmpty()) {
+			zeroMemory(_authKeyStrings->g_a.data(), _authKeyStrings->g_a.size());
+		}
+		zeroMemory(_authKeyStrings->auth_key.data(), _authKeyStrings->auth_key.size());
 		_authKeyStrings.reset();
 	}
 }
@@ -3031,6 +3041,7 @@ void ConnectionPrivate::unlockKey() {
 }
 
 ConnectionPrivate::~ConnectionPrivate() {
+	clearAuthKeyData();
 	t_assert(_finished && _conn == nullptr && _conn4 == nullptr && _conn6 == nullptr);
 }
 
diff --git a/Telegram/SourceFiles/mtproto/connection.h b/Telegram/SourceFiles/mtproto/connection.h
index 54e3940d8..59704ea9e 100644
--- a/Telegram/SourceFiles/mtproto/connection.h
+++ b/Telegram/SourceFiles/mtproto/connection.h
@@ -77,7 +77,6 @@ class ConnectionPrivate : public QObject {
 	Q_OBJECT
 
 public:
-
 	ConnectionPrivate(QThread *thread, Connection *owner, SessionData *data, uint32 dc);
 	~ConnectionPrivate();
 
@@ -89,7 +88,6 @@ public:
 	QString transport() const;
 
 signals:
-
 	void needToReceive();
 	void needToRestart();
 	void stateChanged(qint32 newState);
@@ -252,7 +250,6 @@ private:
 
 		uchar aesKey[32] = { 0 };
 		uchar aesIV[32] = { 0 };
-		uint32 auth_key[64] = { 0 };
 		MTPlong auth_key_hash;
 
 		uint32 req_num = 0; // sent not encrypted request number
@@ -261,6 +258,7 @@ private:
 	struct AuthKeyCreateStrings {
 		QByteArray dh_prime;
 		QByteArray g_a;
+		AuthKey::Data auth_key = { 0 };
 	};
 	std::unique_ptr<AuthKeyCreateData> _authKeyData;
 	std::unique_ptr<AuthKeyCreateStrings> _authKeyStrings;
diff --git a/Telegram/SourceFiles/mtproto/facade.cpp b/Telegram/SourceFiles/mtproto/facade.cpp
index 561b641c8..7d846bea6 100644
--- a/Telegram/SourceFiles/mtproto/facade.cpp
+++ b/Telegram/SourceFiles/mtproto/facade.cpp
@@ -895,8 +895,12 @@ AuthKeysMap getKeys() {
 	return internal::getAuthKeys();
 }
 
-void setKey(int32 dc, AuthKeyPtr key) {
-	return internal::setAuthKey(dc, key);
+void setKey(int dc, const AuthKey::Data &key) {
+	auto dcId = MTP::bareDcId(dc);
+	auto keyPtr = std::make_shared<MTP::AuthKey>();
+	keyPtr->setDC(dcId);
+	keyPtr->setKey(key);
+	return internal::setAuthKey(dc, std::move(keyPtr));
 }
 
 QReadWriteLock *dcOptionsMutex() {
diff --git a/Telegram/SourceFiles/mtproto/facade.h b/Telegram/SourceFiles/mtproto/facade.h
index 4f2086485..94f49743e 100644
--- a/Telegram/SourceFiles/mtproto/facade.h
+++ b/Telegram/SourceFiles/mtproto/facade.h
@@ -220,7 +220,7 @@ void clearGlobalHandlers();
 void updateDcOptions(const QVector<MTPDcOption> &options);
 
 AuthKeysMap getKeys();
-void setKey(int32 dc, AuthKeyPtr key);
+void setKey(int dc, const AuthKey::Data &key);
 
 QReadWriteLock *dcOptionsMutex();