mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
224 lines
6.1 KiB
C++
224 lines
6.1 KiB
C++
// 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>.
|
|
|
|
#include <QtCore>
|
|
#include <QtTest>
|
|
|
|
#include "SSL.h"
|
|
#include "Timer.h"
|
|
#include "CryptState.h"
|
|
#include "Utils.h"
|
|
|
|
class TestCrypt : public QObject {
|
|
Q_OBJECT
|
|
private slots:
|
|
void initTestCase();
|
|
void cleanupTestCase();
|
|
void testvectors();
|
|
void authcrypt();
|
|
void ivrecovery();
|
|
void reverserecovery();
|
|
void tamper();
|
|
};
|
|
|
|
void TestCrypt::initTestCase() {
|
|
MumbleSSL::initialize();
|
|
}
|
|
|
|
void TestCrypt::cleanupTestCase() {
|
|
MumbleSSL::destroy();
|
|
}
|
|
|
|
void TestCrypt::reverserecovery() {
|
|
CryptState enc, dec;
|
|
enc.genKey();
|
|
|
|
// For our testcase, we're going to FORCE iv
|
|
memset(enc.encrypt_iv, 0x55, AES_BLOCK_SIZE);
|
|
|
|
dec.setKey(enc.raw_key, enc.decrypt_iv, enc.encrypt_iv);
|
|
|
|
unsigned char secret[10] = "abcdefghi";
|
|
unsigned char crypted[512][14];
|
|
unsigned char decr[10];
|
|
|
|
memset(crypted, 0, sizeof(crypted));
|
|
|
|
// OOO recovery (within 15 packets)
|
|
/*
|
|
for(int i=0;i<128;i++) {
|
|
for(int i=0;i<15;i++)
|
|
enc.encrypt(secret, crypted[i], 10);
|
|
|
|
dec.stat_lost = dec.stat_late = 0;
|
|
for(unsigned int i=14;i<=15;i--) {
|
|
QVERIFY(dec.decrypt(crypted[i], decr, 14));
|
|
QCOMPARE(dec.stat_lost, i);
|
|
QCOMPARE(dec.stat_late, 14-i);
|
|
}
|
|
for(int i=0;i<15;i++)
|
|
QVERIFY(!dec.decrypt(crypted[i], decr, 14));
|
|
}
|
|
*/
|
|
// OOO recovery up to 30 packets, but NOT beyond
|
|
|
|
int i;
|
|
|
|
for (i=0;i<128;i++)
|
|
enc.encrypt(secret, crypted[i], 10);
|
|
|
|
for (i=0;i<30;i++)
|
|
QVERIFY(dec.decrypt(crypted[127-i], decr, 14));
|
|
for (;i<128;i++)
|
|
QVERIFY(!dec.decrypt(crypted[127-i], decr, 14));
|
|
for (i=0;i<30;i++)
|
|
QVERIFY(!dec.decrypt(crypted[127-i], decr, 14));
|
|
|
|
|
|
// Extensive replay attack test
|
|
for (i=0;i<512;i++)
|
|
enc.encrypt(secret, crypted[i], 10);
|
|
|
|
for (i=0;i<512;i++)
|
|
QVERIFY(dec.decrypt(crypted[i], decr, 14));
|
|
for (i=0;i<512;i++)
|
|
QVERIFY(!dec.decrypt(crypted[i], decr, 14));
|
|
}
|
|
|
|
void TestCrypt::ivrecovery() {
|
|
CryptState enc, dec;
|
|
enc.genKey();
|
|
|
|
// For our testcase, we're going to FORCE iv
|
|
memset(enc.encrypt_iv, 0x55, AES_BLOCK_SIZE);
|
|
|
|
dec.setKey(enc.raw_key, enc.decrypt_iv, enc.encrypt_iv);
|
|
|
|
unsigned char secret[10] = "abcdefghi";
|
|
unsigned char crypted[14];
|
|
unsigned char decr[10];
|
|
|
|
enc.encrypt(secret, crypted, 10);
|
|
|
|
// Can decrypt.
|
|
QVERIFY(dec.decrypt(crypted, decr, 14));
|
|
// .. correctly.
|
|
QVERIFY(memcmp(secret, decr, 10)==0);
|
|
|
|
// But will refuse to reuse same IV.
|
|
QVERIFY(! dec.decrypt(crypted, decr, 14));
|
|
|
|
// Recover from lost packet.
|
|
for (int i=0;i<16;i++)
|
|
enc.encrypt(secret, crypted, 10);
|
|
|
|
QVERIFY(dec.decrypt(crypted, decr, 14));
|
|
|
|
// Wraparound.
|
|
for (int i=0;i<128;i++) {
|
|
dec.uiLost = 0;
|
|
for (int j=0;j<15;j++)
|
|
enc.encrypt(secret, crypted, 10);
|
|
QVERIFY(dec.decrypt(crypted, decr, 14));
|
|
QCOMPARE(dec.uiLost, 14U);
|
|
}
|
|
|
|
QVERIFY(memcmp(enc.encrypt_iv, dec.decrypt_iv, AES_BLOCK_SIZE)==0);
|
|
|
|
// Wrap too far
|
|
for (int i=0;i<257;i++)
|
|
enc.encrypt(secret, crypted, 10);
|
|
|
|
QVERIFY(! dec.decrypt(crypted, decr, 14));
|
|
|
|
// Sync it
|
|
dec.setDecryptIV(enc.encrypt_iv);
|
|
enc.encrypt(secret, crypted, 10);
|
|
|
|
QVERIFY(dec.decrypt(crypted, decr, 14));
|
|
}
|
|
|
|
void TestCrypt::testvectors() {
|
|
// Test vectors are from draft-krovetz-ocb-00.txt
|
|
const unsigned char rawkey[AES_BLOCK_SIZE] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
|
|
|
|
CryptState cs;
|
|
cs.setKey(rawkey, rawkey, rawkey);
|
|
|
|
unsigned char tag[16];
|
|
cs.ocb_encrypt(NULL, NULL, 0, rawkey, tag);
|
|
|
|
const unsigned char blanktag[AES_BLOCK_SIZE] = {0xBF,0x31,0x08,0x13,0x07,0x73,0xAD,0x5E,0xC7,0x0E,0xC6,0x9E,0x78,0x75,0xA7,0xB0};
|
|
for (int i=0;i<AES_BLOCK_SIZE;i++)
|
|
QCOMPARE(tag[i], blanktag[i]);
|
|
|
|
unsigned char source[40];
|
|
unsigned char crypt[40];
|
|
for (int i=0;i<40;i++)
|
|
source[i]=i;
|
|
cs.ocb_encrypt(source, crypt, 40, rawkey, tag);
|
|
const unsigned char longtag[AES_BLOCK_SIZE] = {0x9D,0xB0,0xCD,0xF8,0x80,0xF7,0x3E,0x3E,0x10,0xD4,0xEB,0x32,0x17,0x76,0x66,0x88};
|
|
const unsigned char crypted[40] = {0xF7,0x5D,0x6B,0xC8,0xB4,0xDC,0x8D,0x66,0xB8,0x36,0xA2,0xB0,0x8B,0x32,0xA6,0x36,0x9F,0x1C,0xD3,0xC5,0x22,0x8D,0x79,0xFD,
|
|
0x6C,0x26,0x7F,0x5F,0x6A,0xA7,0xB2,0x31,0xC7,0xDF,0xB9,0xD5,0x99,0x51,0xAE,0x9C
|
|
};
|
|
|
|
for (int i=0;i<AES_BLOCK_SIZE;i++)
|
|
QCOMPARE(tag[i], longtag[i]);
|
|
|
|
for (int i=0;i<40;i++)
|
|
QCOMPARE(crypt[i], crypted[i]);
|
|
}
|
|
|
|
void TestCrypt::authcrypt() {
|
|
for (int len=0;len<128;len++) {
|
|
const unsigned char rawkey[AES_BLOCK_SIZE] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
|
|
const unsigned char nonce[AES_BLOCK_SIZE] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
|
|
CryptState cs;
|
|
cs.setKey(rawkey, nonce, nonce);
|
|
|
|
STACKVAR(unsigned char, src, len);
|
|
for (int i=0;i<len;i++)
|
|
src[i] = (i + 1);
|
|
|
|
unsigned char enctag[AES_BLOCK_SIZE];
|
|
unsigned char dectag[AES_BLOCK_SIZE];
|
|
STACKVAR(unsigned char, encrypted, len);
|
|
STACKVAR(unsigned char, decrypted, len);
|
|
|
|
cs.ocb_encrypt(src, encrypted, len, nonce, enctag);
|
|
cs.ocb_decrypt(encrypted, decrypted, len, nonce, dectag);
|
|
|
|
for (int i=0;i<AES_BLOCK_SIZE;i++)
|
|
QCOMPARE(enctag[i], dectag[i]);
|
|
|
|
for (int i=0;i<len;i++)
|
|
QCOMPARE(src[i], decrypted[i]);
|
|
}
|
|
}
|
|
|
|
void TestCrypt::tamper() {
|
|
const unsigned char rawkey[AES_BLOCK_SIZE] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
|
|
const unsigned char nonce[AES_BLOCK_SIZE] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
|
|
CryptState cs;
|
|
cs.setKey(rawkey, nonce, nonce);
|
|
|
|
const unsigned char msg[] = "It was a funky funky town!";
|
|
int len = sizeof(msg);
|
|
|
|
STACKVAR(unsigned char, encrypted, len+4);
|
|
STACKVAR(unsigned char, decrypted, len);
|
|
cs.encrypt(msg, encrypted, len);
|
|
|
|
for (int i=0;i<len*8;i++) {
|
|
encrypted[i/8] ^= 1 << (i % 8);
|
|
QVERIFY(! cs.decrypt(encrypted, decrypted, len+4));
|
|
encrypted[i/8] ^= 1 << (i % 8);
|
|
}
|
|
QVERIFY(cs.decrypt(encrypted, decrypted, len+4));
|
|
}
|
|
|
|
QTEST_MAIN(TestCrypt)
|
|
#include "TestCrypt.moc"
|