Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a55ae3d authored by Seth Moore's avatar Seth Moore
Browse files

Fix flaky corrupted padding tests

It's possible that corrupted ciphertext decrypts just fine. e.g. the
output ends with "0x01".

However, the chances of this happening are relatively low
(roughly 1/256). Corrupt the ciphertext up to 8 times, ensuring that
the likelihood of multiple successful decryptions is so miniscule that
it's effectively impossible.

Test: Ran *PaddingCorrupted tests 50000 times
Change-Id: If40ecd7817819921c020ea9b86ada18c4c77ea55
parent 5d3dd756
Loading
Loading
Loading
Loading
+54 −14
Original line number Diff line number Diff line
@@ -71,6 +71,12 @@ namespace {

bool check_patchLevels = false;

// The maximum number of times we'll attempt to verify that corruption
// of an ecrypted blob results in an error. Retries are necessary as there
// is a small (roughly 1/256) chance that corrupting ciphertext still results
// in valid PKCS7 padding.
constexpr size_t kMaxPaddingCorruptionRetries = 8;

template <TagType tag_type, Tag tag, typename ValueT>
bool contains(const vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag,
              ValueT expected_value) {
@@ -4376,11 +4382,22 @@ TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
    string ciphertext = EncryptMessage(message, params);
    EXPECT_EQ(16U, ciphertext.size());
    EXPECT_NE(ciphertext, message);

    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
        ++ciphertext[ciphertext.size() / 2];

        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
        string plaintext;
    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
        ErrorCode error = Finish(message, &plaintext);
        if (error == ErrorCode::INVALID_INPUT_LENGTH) {
            // This is the expected error, we can exit the test now.
            return;
        } else {
            // Very small chance we got valid decryption, so try again.
            ASSERT_EQ(error, ErrorCode::OK);
        }
    }
    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}

vector<uint8_t> CopyIv(const AuthorizationSet& set) {
@@ -5343,15 +5360,27 @@ TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
    string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
    EXPECT_EQ(8U, ciphertext.size());
    EXPECT_NE(ciphertext, message);
    ++ciphertext[ciphertext.size() / 2];

    AuthorizationSetBuilder begin_params;
    begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
    begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);

    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
        ++ciphertext[ciphertext.size() / 2];

        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
        string plaintext;
        EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
        ErrorCode error = Finish(&plaintext);
        if (error == ErrorCode::INVALID_ARGUMENT) {
            // This is the expected error, we can exit the test now.
            return;
        } else {
            // Very small chance we got valid decryption, so try again.
            ASSERT_EQ(error, ErrorCode::OK);
        }
    }
    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}

struct TripleDesTestVector {
@@ -5679,16 +5708,27 @@ TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
    string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
    EXPECT_EQ(8U, ciphertext.size());
    EXPECT_NE(ciphertext, message);
    ++ciphertext[ciphertext.size() / 2];

    auto begin_params = AuthorizationSetBuilder()
                                .BlockMode(BlockMode::CBC)
                                .Padding(PaddingMode::PKCS7)
                                .Authorization(TAG_NONCE, iv);

    for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
        ++ciphertext[ciphertext.size() / 2];
        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
        string plaintext;
        EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
        ErrorCode error = Finish(&plaintext);
        if (error == ErrorCode::INVALID_ARGUMENT) {
            // This is the expected error, we can exit the test now.
            return;
        } else {
            // Very small chance we got valid decryption, so try again.
            ASSERT_EQ(error, ErrorCode::OK);
        }
    }
    FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}

/*