// 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 . #include #include #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