risingwavelabs/risingwave · error · CryptographyError
{stage:?} stage, reason: {reason}
Error message
{stage:?} stage, reason: {reason} What it means
CryptographyError is a thiserror error wrapper for openssl failures in encrypt/decrypt scalar functions. Its message reports which stage (Encrypt or Decrypt) failed plus the underlying openssl::error::ErrorStack as the source, so the real cause (key size, padding, bad input length) is in the chained source.
Source
Thrown at src/expr/impl/src/scalar/encrypt.rs:192
config.eval(data, CryptographyStage::Decrypt)
}
#[function(
"encrypt(bytea, bytea, varchar) -> bytea",
prebuild = "CipherConfig::parse_cipher_config($1, $2)?"
)]
fn encrypt(data: &[u8], config: &CipherConfig) -> Result<Box<[u8]>, CryptographyError> {
config.eval(data, CryptographyStage::Encrypt)
}
#[derive(Debug)]
enum CryptographyStage {
Encrypt,
Decrypt,
}
#[derive(Debug, thiserror::Error)]
#[error("{stage:?} stage, reason: {reason}")]
struct CryptographyError {
pub stage: CryptographyStage,
#[source]
pub reason: openssl::error::ErrorStack,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_decrypt() {
let data = b"hello world";
let mode = "aes";
let config = CipherConfig::parse_cipher_config(
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" as &[u8],
mode,View on GitHub (pinned to 6469eb736d)
Solutions
- Inspect the chained openssl::error::ErrorStack source (`err.source()`) for the concrete OpenSSL reason code.
- Verify the encryption key length matches the algorithm (16/24/32 bytes for AES-128/192/256).
- Ensure ciphertext length is a valid multiple of the cipher block size and padding settings match between encrypt and decrypt.
Example fix
// before let key = user_key.as_bytes(); // arbitrary length // after let key = derive_key(user_key.as_bytes(), 32); // pad/hash to required AES-256 key length
Defensive patterns
Strategy: try-catch
Validate before calling
if key.len() != 16 && key.len() != 24 && key.len() != 32 {
return Err("AES key must be 16, 24, or 32 bytes".into());
} Try / catch
match encrypt_fn(key, plaintext) {
Ok(ct) => ct,
Err(e) => {
// inspect openssl source chain
let mut src = e.source();
while let Some(s) = src { eprintln!("caused by: {s}"); src = s.source(); }
return Err(anyhow!("crypto failed: {e}"));
}
} Prevention
- Validate key length against the cipher before encrypting/decrypting.
- Use the same algorithm, padding, and IV parameters on both encrypt and decrypt sides.
- Log the openssl ErrorStack reason codes when diagnosing.
When it happens
Trigger: Invoking the encrypt() or decrypt() SQL functions when the OpenSSL crypto operation returns an ErrorStack — e.g. wrong key length for AES, input not a multiple of the block size, or corrupted ciphertext during decrypt.
Common situations: Encrypting data with a key that doesn't match the required AES key size; decrypting data encrypted elsewhere with different parameters; OpenSSL misconfiguration or FIPS provider restrictions.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- failed to encrypt or decrypt the secret
- secret_store_private_key is not configured
- Unable to setup an SSL connection
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/97f805d6a0f4f989.
Report an issue: GitHub.