From 9c247e83bd2241caddcffac926c4775d5b143940 Mon Sep 17 00:00:00 2001 From: MikalaiR Date: Thu, 18 Feb 2016 17:25:11 +0000 Subject: KuznechikCrypt: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@16305 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Kuzne4ikCrypt/src/encrypt.cpp | 234 ++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 plugins/Kuzne4ikCrypt/src/encrypt.cpp (limited to 'plugins/Kuzne4ikCrypt/src/encrypt.cpp') diff --git a/plugins/Kuzne4ikCrypt/src/encrypt.cpp b/plugins/Kuzne4ikCrypt/src/encrypt.cpp new file mode 100644 index 0000000000..62b3b3a24c --- /dev/null +++ b/plugins/Kuzne4ikCrypt/src/encrypt.cpp @@ -0,0 +1,234 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-16 Miranda NG project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +#include "..\..\..\libs\zlib\src\zlib.h" + +struct ExternalKey +{ + BYTE m_key[KEY_LENGTH]; + DWORD m_crc32; + BYTE slack[BLOCK_SIZE - sizeof(DWORD)]; +}; + +CCrypt::CCrypt() : + m_password("Miranda") +{} + +CCrypt::~CCrypt() +{ + if (m_valid) + { + free_ecb(m_ctx); + getRandomBytes(m_key, KEY_LENGTH); + } +} + +void CCrypt::destroy() +{ + delete this; +} + +size_t CCrypt::getKeyLength() +{ + return sizeof(ExternalKey); +} + +bool CCrypt::getKey(BYTE *pKey, size_t cbKeyLen) +{ + if (!m_valid || cbKeyLen < sizeof(ExternalKey)) + return false; + + ExternalKey tmp = { 0 }; + memcpy(&tmp.m_key, m_key, KEY_LENGTH); + tmp.m_crc32 = crc32(0xAbbaDead, (LPCBYTE)m_password.GetString(), m_password.GetLength()); + getRandomBytes(tmp.slack, sizeof(tmp.slack)); + + BYTE tmpHash[32]; + slow_hash(m_password, m_password.GetLength(), tmpHash); + + BYTE ctx[kEcb14ContextLen]; + init_ecb_14(tmpHash, ctx); + bool val = !encrypt_ecb(ctx, (BYTE*)&tmp, pKey, cbKeyLen); + free_ecb(ctx); + + return val; +} + +bool CCrypt::setKey(const BYTE *pKey, size_t cbKeyLen) +{ + // full external key. decode & check password + if (cbKeyLen != sizeof(ExternalKey)) + return false; + + BYTE tmpHash[32]; + slow_hash(m_password, m_password.GetLength(), tmpHash); + + + BYTE ctx[kEcb14ContextLen]; + init_ecb_14(tmpHash, ctx); + + ExternalKey tmp = { 0 }; + + decrypt_ecb(ctx, (BYTE*)pKey, (BYTE*)&tmp, sizeof(tmp)); + + free_ecb(ctx); + + if (tmp.m_crc32 != crc32(0xAbbaDead, (LPCBYTE)m_password.GetString(), m_password.GetLength())) + return false; + + m_valid = true; + memcpy(m_key, &tmp.m_key, KEY_LENGTH); + init_ecb_14(m_key, m_ctx); + + return m_valid = true; +} + +bool CCrypt::generateKey(void) +{ + BYTE tmp[KEY_LENGTH]; + if (!getRandomBytes(tmp, sizeof(tmp))) + return false; + + memcpy(m_key, tmp, KEY_LENGTH); + init_ecb_14(m_key, m_ctx); + return m_valid = true; +} + +void CCrypt::purgeKey(void) +{ + memset(m_key, 0, sizeof(m_key)); + m_valid = false; +} + +// checks the master password (in utf-8) +bool CCrypt::checkPassword(const char *pszPassword) +{ + return m_password == pszPassword; +} + +// sets the master password (in utf-8) +void CCrypt::setPassword(const char *pszPassword) +{ + m_password = (pszPassword == NULL) ? "Miranda" : pszPassword; +} + +// result must be freed using mir_free or assigned to mir_ptr +BYTE* CCrypt::encodeString(const char *src, size_t *cbResultLen) +{ + if (!m_valid || src == NULL) { + if (cbResultLen) + *cbResultLen = 0; + return NULL; + } + + return encodeBuffer(src, mir_strlen(src)+1, cbResultLen); +} + +BYTE* CCrypt::encodeBuffer(const void *src, size_t cbLen, size_t *cbResultLen) +{ + if (cbResultLen) + *cbResultLen = 0; + + if (!m_valid || src == NULL || cbLen >= 0xFFFE) + return NULL; + + BYTE *tmpBuf = (BYTE*)_alloca(cbLen + 2); + *(PWORD)tmpBuf = (WORD)cbLen; + memcpy(tmpBuf + 2, src, cbLen); + cbLen += 2; + size_t rest = cbLen % BLOCK_SIZE; + if (rest) + cbLen += BLOCK_SIZE - rest; + + BYTE *result = (BYTE*)mir_alloc(cbLen); + + if (encrypt_ecb(m_ctx, tmpBuf, LPBYTE(result), cbLen)) { + mir_free(result); + return NULL; + } + + if (cbResultLen) + *cbResultLen = cbLen; + return result; +} + +char* CCrypt::decodeString(const BYTE *pBuf, size_t bufLen, size_t *cbResultLen) +{ + size_t resLen; + char *result = (char*)decodeBuffer(pBuf, bufLen, &resLen); + if (result) { + if (result[resLen-1] != 0) { // smth went wrong + mir_free(result); + return NULL; + } + } + + if (cbResultLen) + *cbResultLen = resLen; + return result; +} + +void* CCrypt::decodeBuffer(const BYTE *pBuf, size_t bufLen, size_t *cbResultLen) +{ + if (cbResultLen) + *cbResultLen = 0; + + if (!m_valid || pBuf == NULL || (bufLen % BLOCK_SIZE) != 0) + return NULL; + + char *result = (char*)mir_alloc(bufLen + 1); + + if (decrypt_ecb(m_ctx, LPBYTE(pBuf), (BYTE*)result, bufLen)) { + mir_free(result); + return NULL; + } + + result[bufLen] = 0; + WORD cbLen = *(PWORD)result; + if (cbLen > bufLen) { + mir_free(result); + return NULL; + } + + memmove(result, result + 2, cbLen); + if (cbResultLen) + *cbResultLen = cbLen; + return result; +} + +static MICryptoEngine* __cdecl builder() +{ + return new CCrypt(); +} + +int LoadEncryptionModule(void) +{ + CRYPTO_PROVIDER cp = { sizeof(cp) }; + cp.pszName = "Kuznechik"; + cp.pszDescr = LPGEN("Kuznechik (GOST P 34.12-2015) crypto provider"); + cp.pFactory = builder; + Crypto_RegisterEngine(&cp); + return 0; +} -- cgit v1.2.3