123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- /* Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- - Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- - Neither the name of the Mumble Developers nor the names of its
- contributors may be used to endorse or promote products derived from this
- software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- * 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 "mumlib/CryptState.hpp"
- #include <cstring>
- #include <cstdint>
- using namespace std;
- mumlib::CryptState::CryptState() {
- for (int i = 0; i < 0x100; i++)
- decrypt_history[i] = 0;
- bInit = false;
- uiGood = uiLate = uiLost = uiResync = 0;
- uiRemoteGood = uiRemoteLate = uiRemoteLost = uiRemoteResync = 0;
- }
- bool mumlib::CryptState::isValid() const {
- return bInit;
- }
- void mumlib::CryptState::setKey(const unsigned char *rkey, const unsigned char *eiv, const unsigned char *div) {
- memcpy(raw_key, rkey, AES_BLOCK_SIZE);
- memcpy(encrypt_iv, eiv, AES_BLOCK_SIZE);
- memcpy(decrypt_iv, div, AES_BLOCK_SIZE);
- AES_set_encrypt_key(raw_key, 128, &encrypt_key);
- AES_set_decrypt_key(raw_key, 128, &decrypt_key);
- bInit = true;
- }
- void mumlib::CryptState::setDecryptIV(const unsigned char *iv) {
- memcpy(decrypt_iv, iv, AES_BLOCK_SIZE);
- }
- void mumlib::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;
- ocb_encrypt(source, dst + 4, plain_length, encrypt_iv, tag);
- dst[0] = encrypt_iv[0];
- dst[1] = tag[0];
- dst[2] = tag[1];
- dst[3] = tag[2];
- }
- bool mumlib::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;
- }
- }
- ocb_decrypt(source + 4, dst, plain_length, decrypt_iv, tag);
- if (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;
- return true;
- }
- #define BLOCKSIZE 2
- #define SHIFTBITS 63
- typedef uint64_t subblock;
- #define SWAP64(x) ({register uint64_t __out, __in = (x); __asm__("bswap %q0" : "=r"(__out) : "0"(__in)); __out;})
- #define SWAPPED(x) SWAP64(x)
- typedef subblock keyblock[BLOCKSIZE];
- 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);
- void mumlib::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;
- // 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));
- 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);
- }
- void mumlib::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;
- // 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);
- S3(delta);
- XOR(tmp, delta, checksum);
- AESencrypt(tmp, tag, &encrypt_key);
- }
|