Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Geng <terry@terriex.com>2020-06-03 13:54:38 +0300
committerTerry Geng <terry@terriex.com>2020-06-06 15:37:59 +0300
commite90eb8c4cd7edc0cd3eddafac622edc45efff794 (patch)
treedd737a6399ef4702de73b82e831307be1ec79836 /src/CryptState.cpp
parent5f421e64f7644be2598c15c75d5767e931b3c8a3 (diff)
src: Made CryptState an abstract class, in order to support multiple crypto types in the future. Moved all crypto-related files into src/crypto.
Diffstat (limited to 'src/CryptState.cpp')
-rw-r--r--src/CryptState.cpp323
1 files changed, 0 insertions, 323 deletions
diff --git a/src/CryptState.cpp b/src/CryptState.cpp
deleted file mode 100644
index 519688fd7..000000000
--- a/src/CryptState.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-// Copyright 2005-2020 The Mumble Developers. All rights reserved.
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file at the root of the
-// Mumble source tree or at <https://www.mumble.info/LICENSE>.
-
-/*
- * This code implements OCB-AES128.
- * In the US, OCB is covered by patents. The inventor has given a license
- * to all programs distributed under the GPL.
- * Mumble is BSD (revised) licensed, meaning you can use the code in a
- * closed-source program. If you do, you'll have to either replace
- * OCB with something else or get yourself a license.
- */
-
-#include <QtCore/QtGlobal>
-
-#ifndef __LP64__
-# ifdef Q_OS_WIN
-# include "win.h"
-# include <winsock2.h>
-# else
-# include <arpa/inet.h>
-# endif
-#endif
-
-#include "CryptState.h"
-
-#include "ByteSwap.h"
-
-#include <cstring>
-
-#include <openssl/rand.h>
-
-CryptState::CryptState() {
- for (int i=0;i<0x100;i++)
- decrypt_history[i] = 0;
- bInit = false;
- memset(raw_key, 0, AES_KEY_SIZE_BYTES);
- memset(encrypt_iv, 0, AES_BLOCK_SIZE);
- memset(decrypt_iv, 0, AES_BLOCK_SIZE);
- uiGood=uiLate=uiLost=uiResync=0;
- uiRemoteGood=uiRemoteLate=uiRemoteLost=uiRemoteResync=0;
-}
-
-bool CryptState::isValid() const {
- return bInit;
-}
-
-void CryptState::genKey() {
- RAND_bytes(raw_key, AES_KEY_SIZE_BYTES);
- RAND_bytes(encrypt_iv, AES_BLOCK_SIZE);
- RAND_bytes(decrypt_iv, AES_BLOCK_SIZE);
- AES_set_encrypt_key(raw_key, AES_KEY_SIZE_BITS, &encrypt_key);
- AES_set_decrypt_key(raw_key, AES_KEY_SIZE_BITS, &decrypt_key);
- bInit = true;
-}
-
-void CryptState::setKey(const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div) {
- memcpy(raw_key, rkey, AES_KEY_SIZE_BYTES);
- memcpy(encrypt_iv, eiv, AES_BLOCK_SIZE);
- memcpy(decrypt_iv, div, AES_BLOCK_SIZE);
- AES_set_encrypt_key(raw_key, AES_KEY_SIZE_BITS, &encrypt_key);
- AES_set_decrypt_key(raw_key, AES_KEY_SIZE_BITS, &decrypt_key);
- bInit = true;
-}
-
-void CryptState::setDecryptIV(const unsigned char *iv) {
- memcpy(decrypt_iv, iv, AES_BLOCK_SIZE);
-}
-
-bool CryptState::encrypt(const unsigned char *source, unsigned char *dst, unsigned int plain_length) {
- unsigned char tag[AES_BLOCK_SIZE];
-
- // First, increase our IV.
- for (int i=0;i<AES_BLOCK_SIZE;i++)
- if (++encrypt_iv[i])
- break;
-
- if (!ocb_encrypt(source, dst+4, plain_length, encrypt_iv, tag)) {
- return false;
- }
-
- dst[0] = encrypt_iv[0];
- dst[1] = tag[0];
- dst[2] = tag[1];
- dst[3] = tag[2];
- return true;
-}
-
-bool CryptState::decrypt(const unsigned char *source, unsigned char *dst, unsigned int crypted_length) {
- if (crypted_length < 4)
- return false;
-
- unsigned int plain_length = crypted_length - 4;
-
- unsigned char saveiv[AES_BLOCK_SIZE];
- unsigned char ivbyte = source[0];
- bool restore = false;
- unsigned char tag[AES_BLOCK_SIZE];
-
- int lost = 0;
- int late = 0;
-
- memcpy(saveiv, decrypt_iv, AES_BLOCK_SIZE);
-
- if (((decrypt_iv[0] + 1) & 0xFF) == ivbyte) {
- // In order as expected.
- if (ivbyte > decrypt_iv[0]) {
- decrypt_iv[0] = ivbyte;
- } else if (ivbyte < decrypt_iv[0]) {
- decrypt_iv[0] = ivbyte;
- for (int i=1;i<AES_BLOCK_SIZE;i++)
- if (++decrypt_iv[i])
- break;
- } else {
- return false;
- }
- } else {
- // This is either out of order or a repeat.
-
- int diff = ivbyte - decrypt_iv[0];
- if (diff > 128)
- diff = diff-256;
- else if (diff < -128)
- diff = diff+256;
-
- if ((ivbyte < decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
- // Late packet, but no wraparound.
- late = 1;
- lost = -1;
- decrypt_iv[0] = ivbyte;
- restore = true;
- } else if ((ivbyte > decrypt_iv[0]) && (diff > -30) && (diff < 0)) {
- // Last was 0x02, here comes 0xff from last round
- late = 1;
- lost = -1;
- decrypt_iv[0] = ivbyte;
- for (int i=1;i<AES_BLOCK_SIZE;i++)
- if (decrypt_iv[i]--)
- break;
- restore = true;
- } else if ((ivbyte > decrypt_iv[0]) && (diff > 0)) {
- // Lost a few packets, but beyond that we're good.
- lost = ivbyte - decrypt_iv[0] - 1;
- decrypt_iv[0] = ivbyte;
- } else if ((ivbyte < decrypt_iv[0]) && (diff > 0)) {
- // Lost a few packets, and wrapped around
- lost = 256 - decrypt_iv[0] + ivbyte - 1;
- decrypt_iv[0] = ivbyte;
- for (int i=1;i<AES_BLOCK_SIZE;i++)
- if (++decrypt_iv[i])
- break;
- } else {
- return false;
- }
-
- if (decrypt_history[decrypt_iv[0]] == decrypt_iv[1]) {
- memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
- return false;
- }
- }
-
- bool ocb_success = ocb_decrypt(source+4, dst, plain_length, decrypt_iv, tag);
-
- if (!ocb_success || memcmp(tag, source+1, 3) != 0) {
- memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
- return false;
- }
- decrypt_history[decrypt_iv[0]] = decrypt_iv[1];
-
- if (restore)
- memcpy(decrypt_iv, saveiv, AES_BLOCK_SIZE);
-
- uiGood++;
- uiLate += late;
- uiLost += lost;
-
- tLastGood.restart();
- return true;
-}
-
-#if defined(__LP64__)
-
-#define BLOCKSIZE 2
-#define SHIFTBITS 63
-typedef quint64 subblock;
-
-#define SWAPPED(x) SWAP64(x)
-
-#else
-#define BLOCKSIZE 4
-#define SHIFTBITS 31
-typedef quint32 subblock;
-#define SWAPPED(x) htonl(x)
-#endif
-
-typedef subblock keyblock[BLOCKSIZE];
-
-#define HIGHBIT (1<<SHIFTBITS);
-
-
-static void inline XOR(subblock *dst, const subblock *a, const subblock *b) {
- for (int i=0;i<BLOCKSIZE;i++) {
- dst[i] = a[i] ^ b[i];
- }
-}
-
-static void inline S2(subblock *block) {
- subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
- for (int i=0;i<BLOCKSIZE-1;i++)
- block[i] = SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i+1]) >> SHIFTBITS));
- block[BLOCKSIZE-1] = SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87));
-}
-
-static void inline S3(subblock *block) {
- subblock carry = SWAPPED(block[0]) >> SHIFTBITS;
- for (int i=0;i<BLOCKSIZE-1;i++)
- block[i] ^= SWAPPED((SWAPPED(block[i]) << 1) | (SWAPPED(block[i+1]) >> SHIFTBITS));
- block[BLOCKSIZE-1] ^= SWAPPED((SWAPPED(block[BLOCKSIZE-1]) << 1) ^(carry * 0x87));
-}
-
-static void inline ZERO(keyblock &block) {
- for (int i=0;i<BLOCKSIZE;i++)
- block[i]=0;
-}
-
-#define AESencrypt(src,dst,key) AES_encrypt(reinterpret_cast<const unsigned char *>(src),reinterpret_cast<unsigned char *>(dst), key);
-#define AESdecrypt(src,dst,key) AES_decrypt(reinterpret_cast<const unsigned char *>(src),reinterpret_cast<unsigned char *>(dst), key);
-
-bool CryptState::ocb_encrypt(const unsigned char *plain, unsigned char *encrypted, unsigned int len, const unsigned char *nonce, unsigned char *tag) {
- keyblock checksum, delta, tmp, pad;
- bool success = true;
-
- // Initialize
- AESencrypt(nonce, delta, &encrypt_key);
- ZERO(checksum);
-
- while (len > AES_BLOCK_SIZE) {
- S2(delta);
- XOR(tmp, delta, reinterpret_cast<const subblock *>(plain));
- AESencrypt(tmp, tmp, &encrypt_key);
- XOR(reinterpret_cast<subblock *>(encrypted), delta, tmp);
- XOR(checksum, checksum, reinterpret_cast<const subblock *>(plain));
-
- // Counter-cryptanalysis described in section 9 of https://eprint.iacr.org/2019/311
- // For an attack, the second to last block (i.e. the last iteration of this loop)
- // must be all 0 except for the last byte (which may be 0 - 128).
- if (len - AES_BLOCK_SIZE <= AES_BLOCK_SIZE) {
- unsigned char sum = 0;
- for (int i = 0; i < AES_BLOCK_SIZE - 1; ++i) {
- sum |= plain[i];
- }
- success &= sum != 0;
- }
-
- len -= AES_BLOCK_SIZE;
- plain += AES_BLOCK_SIZE;
- encrypted += AES_BLOCK_SIZE;
- }
-
- S2(delta);
- ZERO(tmp);
- tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
- XOR(tmp, tmp, delta);
- AESencrypt(tmp, pad, &encrypt_key);
- memcpy(tmp, plain, len);
- memcpy(reinterpret_cast<unsigned char *>(tmp)+len, reinterpret_cast<const unsigned char *>(pad)+len, AES_BLOCK_SIZE - len);
- XOR(checksum, checksum, tmp);
- XOR(tmp, pad, tmp);
- memcpy(encrypted, tmp, len);
-
- S3(delta);
- XOR(tmp, delta, checksum);
- AESencrypt(tmp, tag, &encrypt_key);
-
- return success;
-}
-
-bool CryptState::ocb_decrypt(const unsigned char *encrypted, unsigned char *plain, unsigned int len, const unsigned char *nonce, unsigned char *tag) {
- keyblock checksum, delta, tmp, pad;
- bool success = true;
-
- // Initialize
- AESencrypt(nonce, delta, &encrypt_key);
- ZERO(checksum);
-
- while (len > AES_BLOCK_SIZE) {
- S2(delta);
- XOR(tmp, delta, reinterpret_cast<const subblock *>(encrypted));
- AESdecrypt(tmp, tmp, &decrypt_key);
- XOR(reinterpret_cast<subblock *>(plain), delta, tmp);
- XOR(checksum, checksum, reinterpret_cast<const subblock *>(plain));
- len -= AES_BLOCK_SIZE;
- plain += AES_BLOCK_SIZE;
- encrypted += AES_BLOCK_SIZE;
- }
-
- S2(delta);
- ZERO(tmp);
- tmp[BLOCKSIZE - 1] = SWAPPED(len * 8);
- XOR(tmp, tmp, delta);
- AESencrypt(tmp, pad, &encrypt_key);
- memset(tmp, 0, AES_BLOCK_SIZE);
- memcpy(tmp, encrypted, len);
- XOR(tmp, tmp, pad);
- XOR(checksum, checksum, tmp);
- memcpy(plain, tmp, len);
-
- // Counter-cryptanalysis described in section 9 of https://eprint.iacr.org/2019/311
- // In an attack, the decrypted last block would need to equal `delta ^ len(128)`.
- // With a bit of luck (or many packets), smaller values than 128 (i.e. non-full blocks) are also
- // feasible, so we check `tmp` instead of `plain`.
- // Since our `len` only ever modifies the last byte, we simply check all remaining ones.
- if (memcmp(tmp, delta, AES_BLOCK_SIZE - 1) == 0) {
- success = false;
- }
-
- S3(delta);
- XOR(tmp, delta, checksum);
- AESencrypt(tmp, tag, &encrypt_key);
-
- return success;
-}