vrl/stdlib/
sha2.rs

1use crate::compiler::function::EnumVariant;
2use crate::compiler::prelude::*;
3use crate::value;
4use sha_2::{Digest, Sha224, Sha256, Sha384, Sha512, Sha512_224, Sha512_256};
5use std::sync::LazyLock;
6
7static DEFAULT_VARIANT: LazyLock<Value> =
8    LazyLock::new(|| Value::Bytes(Bytes::from("SHA-512/256")));
9
10static VARIANT_ENUM: &[EnumVariant] = &[
11    EnumVariant {
12        value: "SHA-224",
13        description: "SHA-224 algorithm",
14    },
15    EnumVariant {
16        value: "SHA-256",
17        description: "SHA-256 algorithm",
18    },
19    EnumVariant {
20        value: "SHA-384",
21        description: "SHA-384 algorithm",
22    },
23    EnumVariant {
24        value: "SHA-512",
25        description: "SHA-512 algorithm",
26    },
27    EnumVariant {
28        value: "SHA-512/224",
29        description: "SHA-512/224 algorithm",
30    },
31    EnumVariant {
32        value: "SHA-512/256",
33        description: "SHA-512/256 algorithm",
34    },
35];
36
37static PARAMETERS: LazyLock<Vec<Parameter>> = LazyLock::new(|| {
38    vec![
39        Parameter::required(
40            "value",
41            kind::BYTES,
42            "The string to calculate the hash for.",
43        ),
44        Parameter::optional(
45            "variant",
46            kind::BYTES,
47            "The variant of the algorithm to use.",
48        )
49        .default(&DEFAULT_VARIANT)
50        .enum_variants(VARIANT_ENUM),
51    ]
52});
53
54fn sha2(value: Value, variant: &Bytes) -> Resolved {
55    let value = value.try_bytes()?;
56    let hash = match variant.as_ref() {
57        b"SHA-224" => encode::<Sha224>(&value),
58        b"SHA-256" => encode::<Sha256>(&value),
59        b"SHA-384" => encode::<Sha384>(&value),
60        b"SHA-512" => encode::<Sha512>(&value),
61        b"SHA-512/224" => encode::<Sha512_224>(&value),
62        b"SHA-512/256" => encode::<Sha512_256>(&value),
63        _ => unreachable!("enum invariant"),
64    };
65    Ok(hash.into())
66}
67
68#[derive(Clone, Copy, Debug)]
69pub struct Sha2;
70
71fn variants() -> Vec<Value> {
72    vec![
73        value!("SHA-224"),
74        value!("SHA-256"),
75        value!("SHA-384"),
76        value!("SHA-512"),
77        value!("SHA-512/224"),
78        value!("SHA-512/256"),
79    ]
80}
81
82impl Function for Sha2 {
83    fn identifier(&self) -> &'static str {
84        "sha2"
85    }
86
87    fn usage(&self) -> &'static str {
88        "Calculates a [SHA-2](https://en.wikipedia.org/wiki/SHA-2) hash of the `value`."
89    }
90
91    fn category(&self) -> &'static str {
92        Category::Cryptography.as_ref()
93    }
94
95    fn return_kind(&self) -> u16 {
96        kind::BYTES
97    }
98
99    fn parameters(&self) -> &'static [Parameter] {
100        PARAMETERS.as_slice()
101    }
102
103    fn examples(&self) -> &'static [Example] {
104        &[
105            example! {
106                title: "Calculate sha2 hash using default variant",
107                source: r#"sha2("foobar")"#,
108                result: Ok("d014c752bc2be868e16330f47e0c316a5967bcbc9c286a457761d7055b9214ce"),
109            },
110            example! {
111                title: "Calculate sha2 hash with SHA-512/224",
112                source: r#"sha2("foo", variant: "SHA-512/224")"#,
113                result: Ok("d68f258d37d670cfc1ec1001a0394784233f88f056994f9a7e5e99be"),
114            },
115            example! {
116                title: "Calculate sha2 hash with SHA-384",
117                source: r#"sha2("foobar", "SHA-384")"#,
118                result: Ok(
119                    "3c9c30d9f665e74d515c842960d4a451c83a0125fd3de7392d7b37231af10c72ea58aedfcdf89a5765bf902af93ecf06",
120                ),
121            },
122        ]
123    }
124
125    fn compile(
126        &self,
127        state: &state::TypeState,
128        _ctx: &mut FunctionCompileContext,
129        arguments: ArgumentList,
130    ) -> Compiled {
131        let value = arguments.required("value");
132        let variant = arguments
133            .optional_enum("variant", &variants(), state)?
134            .unwrap_or_else(|| DEFAULT_VARIANT.clone())
135            .try_bytes()
136            .expect("variant not bytes");
137
138        Ok(Sha2Fn { value, variant }.as_expr())
139    }
140}
141
142#[derive(Debug, Clone)]
143struct Sha2Fn {
144    value: Box<dyn Expression>,
145    variant: Bytes,
146}
147
148impl FunctionExpression for Sha2Fn {
149    fn resolve(&self, ctx: &mut Context) -> Resolved {
150        let value = self.value.resolve(ctx)?;
151        let variant = &self.variant;
152
153        sha2(value, variant)
154    }
155
156    fn type_def(&self, _: &state::TypeState) -> TypeDef {
157        TypeDef::bytes().infallible()
158    }
159}
160
161#[inline]
162fn encode<T: Digest>(value: &[u8]) -> String {
163    hex::encode(T::digest(value))
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    test_function![
171        sha2 => Sha2;
172
173        sha2 {
174             args: func_args![value: "foo"],
175             want: Ok("d58042e6aa5a335e03ad576c6a9e43b41591bfd2077f72dec9df7930e492055d"),
176             tdef: TypeDef::bytes().infallible(),
177         }
178
179        sha2_224 {
180            args: func_args![value: "foo",
181                             variant: "SHA-224"
182            ],
183            want: Ok("0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db"),
184            tdef: TypeDef::bytes().infallible(),
185        }
186
187        sha2_256 {
188             args: func_args![value: "foo",
189                              variant: "SHA-256"
190             ],
191             want: Ok("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"),
192             tdef: TypeDef::bytes().infallible(),
193         }
194
195        sha2_385 {
196            args: func_args![value: "foo",
197                             variant: "SHA-384"
198            ],
199            want: Ok("98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb"),
200            tdef: TypeDef::bytes().infallible(),
201        }
202
203        sha2_512 {
204             args: func_args![value: "foo",
205                              variant: "SHA-512"
206             ],
207             want: Ok("f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7"),
208             tdef: TypeDef::bytes().infallible(),
209         }
210
211        sha2_512_224 {
212             args: func_args![value: "foo",
213                              variant: "SHA-512/224"
214             ],
215             want: Ok("d68f258d37d670cfc1ec1001a0394784233f88f056994f9a7e5e99be"),
216             tdef: TypeDef::bytes().infallible(),
217         }
218
219        sha2_512_256 {
220             args: func_args![value: "foo",
221                              variant: "SHA-512/256"
222             ],
223             want: Ok("d58042e6aa5a335e03ad576c6a9e43b41591bfd2077f72dec9df7930e492055d"),
224             tdef: TypeDef::bytes().infallible(),
225         }
226    ];
227}