As mentioned on IRC, I'd prefer the fallback to be a generic CryptError (or some better name) that gets the ERR_reason_error_string if available.

```python
    def _handle_error(self):
        code = self.lib.ERR_get_error()
        lib = self.lib.ERR_GET_LIB(code)
        func = self.lib.ERR_GET_FUNC(code)
        reason = self.lib.ERR_GET_REASON(code)

        if lib == self.lib.ERR_LIB_EVP:
            if func == self.lib.EVP_F_EVP_ENCRYPTFINAL_EX:
                if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
                    raise IncorrectPadding
            elif func == self.lib.EVP_F_EVP_DECRYPTFINAL_EX:
                if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
                    raise IncorrectPadding
        if code:
            reason_string = self.ffi.string(
                self.lib.ERR_reason_error_string(code)
            )
        else:
            reason_string = None
        raise CryptError(reason_string)
```