std::vector GcmWrapper::Decrypt()

in azure-protected-vm-secrets/Windows/BcryptAesWrapper.cpp [325:424]


std::vector<unsigned char> GcmWrapper::Decrypt(const std::vector<unsigned char> &ciphertext, AesChainingInfo *chainingInfo) const
{
    DWORD bytesDone = 0;    
    long long returnDataLength = 0;
    long long ctxOffset = 0;
    if (chainingInfo == nullptr) {
        throw std::exception("Chaining info must be set before calling Encrypt");
    }
    long long encryptedDataLength = ciphertext.size() - this->authTagLengths.dwMaxLength;
    std::vector<unsigned char> result(encryptedDataLength);
    long numBlocks = __round_up(encryptedDataLength, this->blockLength) / this->blockLength;
    GcmChainingInfo* gcmChainingInfo = dynamic_cast<GcmChainingInfo*>(chainingInfo);
    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO* authInfo = gcmChainingInfo->GetAuthInfo();
    std::vector<unsigned char> initVector = gcmChainingInfo->GetInitVector();

#ifndef PLATFORM_UNIX
    NTSTATUS bcryptResult = STATUS_SUCCESS;
    // Peel off the auth tag
    std::vector<unsigned char> authTag(this->authTagLengths.dwMaxLength);
    std::copy(
        ciphertext.data() + encryptedDataLength,
        ciphertext.data() + encryptedDataLength + this->authTagLengths.dwMaxLength,
        authTag.data()
    );
    // init aad
    bcryptResult = BCryptDecrypt(
        this->hAesKey,
        nullptr,
        0,
        authInfo,
        initVector.data(),
        initVector.size(),
        nullptr,
        0,
        &bytesDone,
        0
    );
    if (STATUS_SUCCESS != bcryptResult) {
		// CryptographyError class, AES subclass, decryptError
        throw BcryptError(bcryptResult, "BCryptDecrypt failed",
            ErrorCode::CryptographyError_AES_decryptError);
    }

    authInfo->cbAuthData = 0;
    authInfo->pbAuthData = nullptr;

    for (long i = 0; i < numBlocks - 1; i++) {
        bytesDone = 0;
        ctxOffset = i * this->blockLength;
        bcryptResult = BCryptDecrypt(
            this->hAesKey,
            (unsigned char*)ciphertext.data() + ctxOffset,
            this->blockLength,
            authInfo,
            initVector.data(),
            initVector.size(),
            result.data() + returnDataLength,
            this->blockLength,
            &bytesDone,
            0
        );
        if (STATUS_SUCCESS != bcryptResult) {
			// CryptographyError class, AES subclass, decryptError
            throw BcryptError(bcryptResult, "BCryptDecrypt failed",
                ErrorCode::CryptographyError_AES_decryptError);
        }
        returnDataLength += bytesDone;
        ctxOffset += this->blockLength;
    }

    authInfo->dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;

    bytesDone = 0;
    authInfo->pbTag = authTag.data();
    authInfo->cbTag = authTag.size();

    bcryptResult = BCryptDecrypt(
        this->hAesKey,
        (unsigned char*)ciphertext.data() + ctxOffset,
        encryptedDataLength - ctxOffset,
        authInfo,
        initVector.data(),
        initVector.size(),
        result.data() + returnDataLength,
        this->blockLength,
        &bytesDone,
        0
    );

    if (STATUS_SUCCESS != bcryptResult) {
		// CryptographyError class, AES subclass, decryptError
        throw BcryptError(bcryptResult, "BCryptDecrypt failed",
            ErrorCode::CryptographyError_AES_decryptError);
    }
    returnDataLength += bytesDone;

    return result;
#else
#endif // !PLATFORM_UNIX
}