summaryrefslogtreecommitdiff
path: root/plugins/Kuzne4ikCrypt/src/encrypt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Kuzne4ikCrypt/src/encrypt.cpp')
-rw-r--r--plugins/Kuzne4ikCrypt/src/encrypt.cpp234
1 files changed, 234 insertions, 0 deletions
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>
+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;
+}