keeper_secrets_manager_core/crypto.rs
1// -*- coding: utf-8 -*-
2// _ __
3// | |/ /___ ___ _ __ ___ _ _ (R)
4// | ' </ -_) -_) '_ \/ -_) '_|
5// |_|\_\___\___| .__/\___|_|
6// |_|
7//
8// Keeper Secrets Manager
9// Copyright 2024 Keeper Security Inc.
10// Contact: sm@keepersecurity.com
11//
12
13pub struct CryptoUtils;
14use std::error::Error;
15use std::vec;
16use cipher::{BlockEncrypt, BlockDecrypt};
17use crate::custom_error::KSMRError;
18use crate::utils;
19use aes::Aes256;
20use aes_gcm::aead::AeadMut;
21use aes_gcm::KeyInit;
22use aes_gcm::{self, AeadCore, Aes256Gcm};
23use base64::{engine::general_purpose::URL_SAFE_NO_PAD, prelude::BASE64_URL_SAFE, Engine as _};
24use block_padding::generic_array::GenericArray;
25use num_bigint::BigUint;
26use ecdsa::signature::Signer;
27use ecdsa::signature::Verifier;
28use p256::elliptic_curve::rand_core::OsRng;
29use p256::pkcs8::EncodePrivateKey;
30use p256::SecretKey;
31use p256::{ecdh::EphemeralSecret, EncodedPoint, PublicKey};
32use p256::{
33 ecdsa::{Signature, SigningKey, VerifyingKey},
34 pkcs8::DecodePrivateKey as _,
35};
36use rand::{Rng, RngCore};
37use sha2::Digest;
38
39// types declared here
40
41// constants are declared here
42const BLOCK_SIZE: usize = 16;
43const AES_256_KEY_SIZE: usize = 32;
44
45/// Pads the given data according to the PKCS#7 padding scheme.
46///
47/// In the PKCS#7 padding scheme, data is padded so that its length is a multiple of the specified block size.
48/// If the input data is empty, the function will pad the data to the full block size. The padding bytes are
49/// filled with the value of the number of padding bytes added.
50///
51/// # Arguments
52///
53/// * `data` - A slice of bytes that you want to pad.
54/// * `block_size_var` - The block size to which the data should be padded.
55///
56/// # Returns
57///
58/// Returns a new `Vec<u8>` containing the original data followed by the appropriate padding bytes.
59///
60/// # Examples
61///
62/// ```
63/// use keeper_secrets_manager_core::crypto::pad_data;
64/// let data = b"YELLOW SUBMARINE";
65/// let block_size = 20;
66/// let padded = pad_data(data, block_size);
67/// assert_eq!(padded, b"YELLOW SUBMARINE\x04\x04\x04\x04");
68///
69/// let empty_data: &[u8] = b"";
70/// let padded_empty = pad_data(empty_data, block_size);
71/// assert_eq!(padded_empty, vec![20; 20]); // 20 padding bytes of value 20
72/// ```
73///
74/// # Panics
75///
76/// This function does not panic, but it assumes that `block_size_var` is greater than zero.
77pub fn pad_data(data: &[u8], block_size_var: usize) -> Vec<u8> {
78 // Calculate the padding length
79 let pad_len = if data.is_empty() || (data.len() % block_size_var == 0) {
80 block_size_var
81 } else {
82 block_size_var - (data.len() % block_size_var)
83 };
84
85 let mut padded_data = Vec::with_capacity(data.len() + pad_len);
86
87 // Copy original data
88 padded_data.extend_from_slice(data);
89
90 // Add padding bytes
91 padded_data.extend(vec![pad_len as u8; pad_len]);
92
93 padded_data
94}
95/// Removes PKCS#7 padding from the given data.
96///
97/// This function checks for and removes padding bytes added to the data according to the PKCS#7 padding scheme.
98/// The last byte of the data indicates how many bytes were added as padding. The function will return an error
99/// if the padding is invalid or if the data is empty.
100///
101/// # Arguments
102///
103/// * `data` - A slice of bytes that contains the padded data.
104///
105/// # Returns
106///
107/// Returns a `Result<Vec<u8>, KSMRError>` where:
108/// - `Ok(Vec<u8>)` contains the unpadded data if the padding is valid.
109/// - `Err(KSMRError)` provides an error message if the padding is invalid or if the data is empty.
110///
111/// # Examples
112///
113/// ```
114/// use keeper_secrets_manager_core::crypto::unpad_data;
115/// let padded_data = b"YELLOW SUBMA\x04\x04\x04\x04";
116/// let unpadded = unpad_data(padded_data).unwrap();
117/// assert_eq!(unpadded, b"YELLOW SUBMA");
118///
119/// let invalid_padded_data = b"YELLOW SUBMARINE\x04\x04\x04\x05"; // Incorrect padding
120/// assert!(unpad_data(invalid_padded_data).is_err());
121///
122/// let empty_data: &[u8] = b"";
123/// assert!(unpad_data(empty_data).is_err()); // Expecting an error for empty data
124/// ```
125///
126/// # Errors
127///
128/// This function will return the following errors:
129/// - `KSMRError::CryptoError("Data is empty")`: If the input data is an empty slice.
130/// - `KSMRError::CryptoError("Invalid padding length: ...")`: If the padding length is out of the valid range.
131/// - `KSMRError::CryptoError("Invalid padding bytes")`: If the padding bytes are not consistent.
132pub fn unpad_data(data: &[u8]) -> Result<Vec<u8>, KSMRError> {
133 let data_len = data.len();
134
135 // Check for empty data
136 if data_len == 0 {
137 return Err(KSMRError::CryptoError("Data is empty".to_string()));
138 }
139
140 let pad_len = data[data_len - 1] as usize;
141
142 if !data[data_len - pad_len..]
143 .iter()
144 .all(|&b| b == pad_len as u8)
145 {
146 return Err(KSMRError::CryptoError("Invalid padding bytes".to_string()));
147 }
148
149 // Return the unpadded data
150 Ok(data[..data_len - pad_len].to_vec())
151}
152
153impl CryptoUtils {
154 /// Pads the given binary data to a multiple of the block size using the PKCS#7 padding scheme.
155 ///
156 /// This function adds padding to the input `data` so its length becomes a multiple of the `BLOCK_SIZE`.
157 /// The padding scheme specifies that each padding byte's value is the total number of padding bytes added.
158 /// If `data` is already a multiple of `BLOCK_SIZE`, an additional full block of padding is appended.
159 ///
160 /// # Arguments
161 ///
162 /// * `data` - A slice of bytes to be padded.
163 ///
164 /// # Returns
165 ///
166 /// A `Vec<u8>` containing the original data followed by the necessary padding bytes.
167 ///
168 /// # Example
169 ///
170 /// ```
171 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
172 /// const BLOCK_SIZE: usize = 16;
173 ///
174 /// // Example with exact block size
175 /// let data = b"YELLOW SUBMARINE";
176 /// let padded_data = CryptoUtils::pad_binary(data);
177 /// assert_eq!(padded_data, b"YELLOW SUBMARINE\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10");
178 ///
179 /// // Example with non-exact block size
180 /// let data = b"HELLO";
181 /// let padded_data = CryptoUtils::pad_binary(data);
182 /// assert_eq!(padded_data, b"HELLO\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b");
183 /// ```
184 ///
185 /// In the first example, the input `"YELLOW SUBMARINE"` is 16 bytes, so an extra block of padding is added.
186 /// In the second, `"HELLO"` is 5 bytes, and padding is added to reach the next multiple of the block size.
187 ///
188 /// # Panics
189 ///
190 /// This function does not panic under normal usage.
191 ///
192 /// # Errors
193 ///
194 /// This function does not return errors.
195 pub fn pad_binary(data: &[u8]) -> Vec<u8> {
196 const BLOCK_SIZE: usize = 16; // Define or pass as argument as needed
197
198 let pad_len = BLOCK_SIZE - (data.len() % BLOCK_SIZE);
199 let mut padded_data = Vec::with_capacity(data.len() + pad_len);
200
201 // Add original data
202 padded_data.extend_from_slice(data);
203
204 // Add padding bytes
205 padded_data.extend(vec![pad_len as u8; pad_len]);
206
207 padded_data
208 }
209
210 /// Removes PKCS#7 padding from the given binary data.
211 ///
212 /// This function removes padding from the input `data` that was added according to the PKCS#7 padding scheme.
213 /// It checks the validity of the padding bytes and returns an error if the padding is invalid. The function assumes
214 /// that the length of the data is a multiple of the `BLOCK_SIZE`.
215 ///
216 /// # Arguments
217 ///
218 /// * `data` - A slice of padded binary data to be unpadded.
219 ///
220 /// # Returns
221 ///
222 /// * `Ok(Vec<u8>)` - The unpadded data if the padding is valid.
223 /// * `Err(&'static str)` - An error message if the padding or data length is invalid.
224 ///
225 /// # Errors
226 ///
227 /// This function returns an error in the following cases:
228 /// - The data is empty.
229 /// - The data length is not a multiple of the `BLOCK_SIZE`.
230 /// - The padding is invalid (either incorrectly formatted or out of bounds).
231 ///
232 /// # Example
233 ///
234 /// ```
235 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
236 /// const BLOCK_SIZE: usize = 16;
237 ///
238 /// // Example with valid padding
239 /// let padded_data = b"YELLOW SUBMARINE\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10";
240 /// let unpadded_data = CryptoUtils::unpad_binary(padded_data).unwrap();
241 /// assert_eq!(unpadded_data, b"YELLOW SUBMARINE");
242 ///
243 /// // Example with invalid padding
244 /// let invalid_padded_data = b"YELLOW SUBMARINE\x05\x05\x05\x05\x06";
245 /// assert!(CryptoUtils::unpad_binary(invalid_padded_data).is_err());
246 /// ```
247 ///
248 /// # Panics
249 ///
250 /// This function does not panic but returns a `Result` in case of errors like invalid padding or improper length.
251 pub fn unpad_binary(data: &[u8]) -> Result<Vec<u8>, KSMRError> {
252 const BLOCK_SIZE: usize = 16; // Define or pass as argument as needed
253
254 let data_len = data.len();
255
256 // Check if the data is empty
257 if data_len == 0 {
258 return Err(KSMRError::CryptoError("Data is empty".to_string()));
259 }
260
261 // Check if the length is a multiple of the block size
262 if data_len % BLOCK_SIZE != 0 {
263 return Err(KSMRError::CryptoError("Invalid data length".to_string()));
264 }
265
266 // Get the padding length from the last byte
267 let pad_len = data[data_len - 1];
268
269 // Validate the padding length
270 if pad_len == 0 || pad_len as usize > BLOCK_SIZE || pad_len as usize > data_len {
271 return Err(KSMRError::CryptoError("Invalid padding".to_string()));
272 }
273
274 // Ensure padding bytes are correct
275 if !data[data_len - pad_len as usize..]
276 .iter()
277 .all(|&b| b == pad_len)
278 {
279 return Err(KSMRError::CryptoError("Invalid padding".to_string()));
280 }
281
282 // Return the unpadded data
283 Ok(data[..data_len - pad_len as usize].to_vec())
284 }
285
286 /// Removes padding from the given binary data.
287 ///
288 /// This function removes padding by interpreting the last byte of the input data as the number of padding bytes added.
289 /// It returns the unpadded data if the padding is valid. The function is simpler than PKCS#7, and it does not verify
290 /// the contents of the padding bytes—just their length.
291 ///
292 /// # Arguments
293 ///
294 /// * `data` - A slice of binary data to be unpadded.
295 ///
296 /// # Returns
297 ///
298 /// * `Ok(Vec<u8>)` - The unpadded data if the padding is valid.
299 /// * `Err(&'static str)` - An error message if the padding or data length is invalid.
300 ///
301 /// # Errors
302 ///
303 /// This function returns an error in the following cases:
304 /// - The data is empty.
305 /// - The padding length (extracted from the last byte) is greater than the length of the data.
306 ///
307 /// # Example
308 ///
309 /// ```
310 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
311 /// let padded_data = b"HELLO WORLD\x04\x04\x04\x04";
312 /// let unpadded_data = CryptoUtils::unpad_char(padded_data).unwrap();
313 /// assert_eq!(unpadded_data, b"HELLO WORLD");
314 /// ```
315 ///
316 /// In this example, the input `padded_data` ends with four padding bytes (`\x04`), which are removed by the function.
317 /// The resulting unpadded data is `"HELLO WORLD"`.
318 ///
319 /// # Errors
320 ///
321 /// * `"Data is empty"` - If the input data is empty.
322 /// * `"Invalid padding length"` - If the padding length exceeds the length of the input data.
323 ///
324 /// # Panics
325 ///
326 /// This function does not panic but returns a `Result` in case of errors.
327 pub fn unpad_char(data: &[u8]) -> Result<Vec<u8>, KSMRError> {
328 if data.is_empty() {
329 return Err(KSMRError::CryptoError("Data is empty".to_string()));
330 }
331
332 let pad_len = data[data.len() - 1] as usize;
333
334 // Ensure padding length is not greater than data length
335 if pad_len == 0 || pad_len > data.len() {
336 return Err(KSMRError::CryptoError("Invalid padding length".to_string()));
337 }
338
339 // Optionally, you could also check that all padding bytes are equal to the padding length
340 if !data[data.len() - pad_len..]
341 .iter()
342 .all(|&b| b == pad_len as u8)
343 {
344 return Err(KSMRError::CryptoError("Invalid padding".to_string()));
345 }
346
347 // Return the unpadded data
348 Ok(data[..data.len() - pad_len].to_vec())
349 }
350
351 /// Converts a byte slice into a `BigUint` integer.
352 ///
353 /// # Parameters
354 ///
355 /// - `b`: A byte slice representing the input bytes to be converted to an integer.
356 ///
357 /// # Returns
358 ///
359 /// This function returns a `Result`:
360 /// - `Ok(BigUint)`: The converted integer on success.
361 /// - `Err(KSMRError)`: An error message if the input is invalid (e.g., empty input or exceeds 16 bytes).
362 ///
363 /// # Errors
364 ///
365 /// - Returns `"Input is empty"` if the provided byte slice is empty.
366 /// - Returns `"Input exceeds maximum length of 16 bytes"` if the input byte slice is longer than 16 bytes.
367 ///
368 /// # Example
369 ///
370 /// ```rust
371 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
372 /// use std::str::FromStr;
373 /// use num_bigint::BigUint;
374 /// let bytes = &[1; 17];
375 /// let result = CryptoUtils::bytes_to_int(bytes).unwrap();
376 /// assert_eq!(result, BigUint::from_str("341616807575530379006368233343265341697").unwrap());
377 /// ```
378 pub fn bytes_to_int(b: &[u8]) -> Result<BigUint, KSMRError> {
379 if b.is_empty() {
380 return Err(KSMRError::InsufficientBytes("Input is empty".to_string()));
381 }
382 let big_number = BigUint::from_bytes_be(b);
383 Ok(big_number)
384 }
385
386 /// Converts a URL-safe Base64 encoded string to a byte vector.
387 ///
388 /// This function decodes a URL-safe Base64 encoded string into a vector of bytes. It automatically
389 /// adds the necessary padding (`=`) to the input string if it's missing, ensuring it conforms to
390 /// Base64 encoding rules. The function also includes optional checks to verify the length of the
391 /// decoded byte vector for specific use cases (e.g., UUIDs).
392 ///
393 /// # Parameters
394 ///
395 /// - `s`: A string slice representing the URL-safe Base64 encoded string to decode.
396 ///
397 /// # Returns
398 ///
399 /// This function returns a `Result`:
400 /// - `Ok(Vec<u8>)`: A vector of bytes resulting from decoding the input string on success.
401 /// - `Err(KSMRError)`: An error variant indicating an issue with decoding, such as invalid Base64 format.
402 ///
403 /// # Errors
404 ///
405 /// - `KSMRError::InvalidBase64`: If the input string fails to decode as valid Base64.
406 /// - `KSMRError::DecodedBytesTooShort`: If the decoded byte array is shorter than the required length
407 /// (e.g., for UUID or other fixed-length conversions).
408 ///
409 /// # Example
410 ///
411 /// ```rust
412 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
413 /// use keeper_secrets_manager_core::custom_error::KSMRError;
414 ///
415 /// fn main() -> Result<(), KSMRError> {
416 /// let url_safe_base64 = "c29tZSBkYXRh"; // Example URL-safe Base64 string
417 ///
418 /// // Convert URL-safe Base64 string to bytes
419 /// let decoded_bytes = CryptoUtils::url_safe_str_to_bytes(url_safe_base64);
420 ///
421 /// // Print the resulting byte vector
422 /// println!("Decoded bytes: {:?}", decoded_bytes);
423 ///
424 /// Ok(())
425 /// }
426 /// ```
427 ///
428 /// # Panics
429 ///
430 /// This function does not panic under normal operation. However, it will return an error if the input string is not valid Base64.
431 ///
432 /// # Notes
433 ///
434 /// - The function automatically adds padding (`=`) to the input string if necessary to conform to Base64 encoding rules.
435 /// - The decoded byte array is optionally validated for minimum length (e.g., at least 8 bytes for UUIDs).
436 pub fn url_safe_str_to_bytes(s: &str) -> Result<Vec<u8>, KSMRError> {
437 // Attempt to decode the URL-safe Base64 string
438 let text = s.replace("+", "-").replace("/", "_");
439 let decoded_bytes = URL_SAFE_NO_PAD
440 .decode(&text)
441 .map_err(|err| KSMRError::DecodeError(err.to_string()));
442 let decoded_bytes = match decoded_bytes {
443 Ok(decoded_bytes) => decoded_bytes,
444 Err(err) => {
445 if err == KSMRError::InvalidBase64 {
446 URL_SAFE_NO_PAD
447 .decode(s)
448 .map_err(|err| KSMRError::DecodeError(err.to_string()))?
449 } else {
450 return Err(err);
451 }
452 }
453 };
454
455 // Optional: Check if the decoded bytes are long enough (e.g., for UUIDs)
456 if decoded_bytes.len() < 8 {
457 return Err(KSMRError::DecodedBytesTooShort);
458 }
459
460 Ok(decoded_bytes)
461 }
462
463 pub fn url_safe_str_to_bytes_trim_padding(s: &str) -> Result<Vec<u8>, KSMRError> {
464 let mut text = s.trim_end_matches("=").to_string();
465 // Attempt to decode the URL-safe Base64 string
466 text = text.replace("+", "-").replace("/", "_");
467 let decoded_bytes = URL_SAFE_NO_PAD
468 .decode(&text)
469 .map_err(|err| KSMRError::DecodeError(err.to_string()));
470 let decoded_bytes = match decoded_bytes {
471 Ok(decoded_bytes) => decoded_bytes,
472 Err(err) => {
473 if err == KSMRError::InvalidBase64 {
474 URL_SAFE_NO_PAD
475 .decode(s)
476 .map_err(|err| KSMRError::DecodeError(err.to_string()))?
477 } else {
478 return Err(err);
479 }
480 }
481 };
482 // Optional: Check if the decoded bytes are long enough (e.g., for UUIDs)
483 if decoded_bytes.len() < 8 {
484 return Err(KSMRError::DecodedBytesTooShort);
485 }
486 Ok(decoded_bytes)
487 }
488
489 #[allow(clippy::needless_doctest_main)]
490 /// Generates a vector of random bytes of the specified length.
491 ///
492 /// # Parameters
493 ///
494 /// - `length`: The desired length of the random byte vector.
495 ///
496 /// # Returns
497 ///
498 /// This function returns a `Vec<u8>` containing `length` random bytes.
499 ///
500 /// # Example
501 ///
502 /// ```rust
503 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
504 /// fn main() {
505 /// let length = 16; // Specify the length of random bytes
506 /// let random_bytes = CryptoUtils::generate_random_bytes(length);
507 ///
508 /// // Print the generated random bytes
509 /// println!("Generated random bytes: {:?}", random_bytes);
510 /// }
511 /// ```
512 ///
513 /// # Panics
514 ///
515 /// This function will panic if `length` is zero.
516 pub fn generate_random_bytes(length: usize) -> Vec<u8> {
517 let mut rng = rand::thread_rng(); // Get a random number generator
518 let mut bytes = vec![0u8; length];
519 rng.fill(&mut bytes[..]);
520 bytes // Return the random bytes
521 }
522
523 #[allow(clippy::needless_doctest_main)]
524 /// Generates a 32-byte random encryption key.
525 ///
526 /// This function is suitable for creating encryption keys for symmetric encryption algorithms,
527 /// such as AES-256, which requires a 256-bit (32-byte) key.
528 ///
529 /// # Returns
530 ///
531 /// This function returns a `Vec<u8>` containing 32 random bytes, which can be used as an encryption key.
532 ///
533 /// # Example
534 ///
535 /// ```rust
536 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
537 /// fn main() {
538 /// let encryption_key = CryptoUtils::generate_encryption_key_bytes();
539 ///
540 /// // Print the generated encryption key
541 /// println!("Generated encryption key: {:?}", encryption_key);
542 /// }
543 /// ```
544 ///
545 /// # Panics
546 ///
547 /// This function does not panic under normal operation since it relies on generating random bytes.
548 pub fn generate_encryption_key_bytes() -> Vec<u8> {
549 Self::generate_random_bytes(32)
550 }
551
552 #[allow(clippy::needless_doctest_main)]
553 /// Converts a byte slice to a URL-safe Base64-encoded string.
554 ///
555 /// This function encodes the given byte slice into a URL-safe Base64 string,
556 /// stripping any trailing padding characters (`=`) that are typically used
557 /// in Base64 encoding. The resulting string can be safely included in URLs.
558 ///
559 /// # Parameters
560 ///
561 /// - `b`: A byte slice that you want to encode to a URL-safe Base64 string.
562 ///
563 /// # Returns
564 ///
565 /// This function returns a `String` containing the URL-safe Base64-encoded representation
566 /// of the input byte slice.
567 ///
568 /// # Example
569 ///
570 /// ```rust
571 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
572 /// fn main() {
573 /// let data = b"Hello, World!";
574 /// let encoded_str = CryptoUtils::bytes_to_url_safe_str(data);
575 ///
576 /// // Print the URL-safe Base64-encoded string
577 /// println!("Encoded URL-safe string: {}", encoded_str);
578 /// }
579 /// ```
580 ///
581 /// # Notes
582 ///
583 /// - The function uses the `BASE64_URL_SAFE` encoder, which ensures that the resulting
584 /// string is safe for use in URLs and does not contain characters that may need
585 /// to be escaped.
586 pub fn bytes_to_url_safe_str(b: &[u8]) -> String {
587 // Encode bytes to URL-safe Base64 and strip padding '=' characters
588 let encoded_value = BASE64_URL_SAFE.encode(b);
589 encoded_value.trim_end_matches('=').to_string()
590 }
591
592 /// Converts a URL-safe Base64-encoded string to a `BigUint` integer.
593 ///
594 /// This function first decodes the URL-safe Base64 string into a byte vector.
595 /// It then converts the resulting byte vector into a `BigUint` integer. The function
596 /// will return an error if the string cannot be decoded or if the resulting byte
597 /// vector cannot be converted to a valid integer.
598 ///
599 /// # Parameters
600 ///
601 /// - `s`: A string slice representing the URL-safe Base64-encoded data.
602 ///
603 /// # Returns
604 ///
605 /// This function returns a `Result`:
606 /// - `Ok(BigUint)`: The decoded integer value on success.
607 /// - `Err(KSMRError)`: An error variant indicating a failure in decoding or conversion.
608 ///
609 /// # Example
610 ///
611 /// ```rust
612 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
613 /// use keeper_secrets_manager_core::custom_error::KSMRError;
614 /// fn main() -> Result<(), KSMRError> {
615 /// let url_safe_str = "AQIDBAUGBwgJCgsMDQ4PEA=="; // Example URL-safe Base64 string
616 ///
617 /// match CryptoUtils::url_safe_str_to_int(url_safe_str) {
618 /// Ok(int_value) => println!("Decoded integer value: {}", int_value),
619 /// Err(err) => println!("Error decoding string: {:?}", err),
620 /// }
621 /// Ok(())
622 /// }
623 /// ```
624 ///
625 /// # Errors
626 ///
627 /// - Returns a `KSMRError::InvalidBase64` if the input string is not valid Base64.
628 /// - Returns `KSMRError::InvalidIntegerConversion` if the decoded byte slice cannot
629 /// be converted to a valid `BigUint` integer.
630 ///
631 /// # Notes
632 ///
633 /// - The function assumes that the input string is a valid URL-safe Base64 string.
634 /// - Any invalid Base64 characters or decoding issues will result in a `KSMRError`.
635 pub fn url_safe_str_to_int(s: &str) -> Result<BigUint, KSMRError> {
636 let bytes = Self::url_safe_str_to_bytes(s)?; // Assuming this function is also updated
637 let int_value = Self::bytes_to_int(&bytes)?; // Now returns KSMRError
638 Ok(int_value)
639 }
640
641 #[allow(clippy::needless_doctest_main)]
642 /// Generates an ECC signing key.
643 ///
644 /// This function generates a random encryption key, converts it to a URL-safe Base64 string,
645 /// then converts the string into an integer. The integer is used to populate the first 16 bytes
646 /// of a 32-byte array, with the remaining 16 bytes set to zeros. This 32-byte array is then used
647 /// to create a `SigningKey` that can be used for ECC-based signing operations.
648 ///
649 /// # Returns
650 ///
651 /// This function returns a `Result`:
652 /// - `Ok(SigningKey)`: A successfully generated `SigningKey` instance, which can be used for ECC signing operations.
653 /// - `Err(KSMRError)`: If any of the operations fail, such as key generation, conversion, or `SigningKey` creation.
654 ///
655 /// # Example
656 ///
657 /// ```rust
658 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust to your actual module path
659 ///
660 /// fn main() {
661 /// let signing_key = CryptoUtils::generate_ecc_keys().unwrap();
662 /// println!("Generated ECC Signing Key: {:?}", signing_key);
663 /// }
664 /// ```
665 ///
666 /// # Panics
667 ///
668 /// This function may panic if:
669 /// - The conversion from URL-safe Base64 string to integer fails.
670 /// - The creation of the `SigningKey` from the byte array fails.
671 ///
672 /// # Notes
673 ///
674 /// - The encryption key used to generate the signing key is created randomly for each call to the function, ensuring that the signing key is unique each time.
675 /// - The final `SigningKey` is based on a 32-byte array, where the first 16 bytes come from the converted integer, and the remaining 16 bytes are filled with zeros.
676 /// - The generated signing key is suitable for use in ECC-based cryptographic operations.
677 pub fn generate_ecc_keys() -> Result<SigningKey, KSMRError> {
678 // Generate encryption key bytes
679 let encryption_key_bytes: Vec<u8> = Self::generate_encryption_key_bytes();
680
681 // Convert bytes to URL-safe Base64 string
682 let private_key_str = Self::bytes_to_url_safe_str(&encryption_key_bytes);
683
684 // Convert URL-safe Base64 string to integer
685 let encryption_key_int = Self::url_safe_str_to_int(&private_key_str).map_err(|_| {
686 KSMRError::CryptoError("Failed to convert URL-safe Base64 string to integer".into())
687 })?;
688
689 // Create a 32-byte array for the SigningKey
690 let mut key_bytes = [0u8; 32];
691
692 // Convert the BigUint encryption_key_int to bytes and copy it to the key_bytes array
693 let int_bytes = encryption_key_int.to_bytes_be(); // This gives 16 bytes
694 key_bytes.copy_from_slice(&int_bytes); // Copy the 16 bytes from the integer
695
696 // Create the SigningKey from the byte array
697 SigningKey::from_bytes(GenericArray::from_slice(&key_bytes))
698 .map_err(|_| KSMRError::CryptoError("Failed to create SigningKey from bytes".into()))
699 }
700
701
702 #[allow(clippy::needless_doctest_main)]
703 /// Derives the public key from a given ECC private key.
704 ///
705 /// This function takes a reference to a `SigningKey` (private key) and derives
706 /// the corresponding public key. The public key is then serialized in uncompressed
707 /// format (X9.62).
708 ///
709 /// # Parameters
710 ///
711 /// - `private_key`: A reference to a `SigningKey`, which represents the ECC private key
712 /// from which the public key will be derived.
713 ///
714 /// # Returns
715 ///
716 /// This function returns a `Vec<u8>` containing the serialized public key in uncompressed
717 /// format.
718 ///
719 /// # Example
720 ///
721 /// ```rust
722 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust to your actual module path
723 ///
724 /// fn main() {
725 /// // Assume you have a valid SigningKey instance
726 /// let private_key = CryptoUtils::generate_ecc_keys().unwrap();
727 ///
728 /// // Get the corresponding public key
729 /// let public_key = CryptoUtils::public_key_ecc(&private_key);
730 ///
731 /// println!("Public Key: {:?}", public_key);
732 /// }
733 /// ```
734 ///
735 /// # Notes
736 ///
737 /// - The uncompressed format of the public key allows for straightforward serialization
738 /// and transmission. It includes the x-coordinate and the y-coordinate of the point
739 /// on the elliptic curve.
740 /// - Ensure that the `SigningKey` provided to this function is valid and has been properly
741 /// initialized before calling this function.
742 pub fn public_key_ecc(private_key: &SigningKey) -> Vec<u8> {
743 // Get the public key from the private key
744 let public_key: VerifyingKey = *private_key.verifying_key();
745
746 // Serialize the public key in uncompressed format (X9.62)
747 let pub_key_bytes = public_key.to_encoded_point(false).as_ref().to_vec();
748
749 pub_key_bytes
750 }
751
752
753 #[allow(clippy::needless_doctest_main)]
754 /// Generates a new ECC private key.
755 ///
756 /// This function generates a new 256-bit (32-byte) private key suitable for ECC operations,
757 /// specifically for the P256 curve. The process involves generating random bytes, converting
758 /// those bytes into a URL-safe Base64 string, and then converting that string into an integer.
759 /// The integer is then used to create the `SigningKey` which represents the ECC private key.
760 ///
761 /// # Returns
762 ///
763 /// This function returns a `Result`:
764 /// - `Ok(SigningKey)`: The successfully generated ECC private key as a `SigningKey`.
765 /// - `Err(KSMRError)`: An error if any step of the key generation process fails, including random byte generation, Base64 conversion, integer conversion, or `SigningKey` creation.
766 ///
767 /// # Example
768 ///
769 /// ```rust
770 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust to your actual module path
771 ///
772 /// fn main() {
773 /// // Generate a new ECC private key
774 /// let private_key = CryptoUtils::generate_private_key_ecc().unwrap();
775 ///
776 /// // Print or use the private key as needed
777 /// println!("Generated Private Key: {:?}", private_key);
778 /// }
779 /// ```
780 ///
781 /// # Notes
782 ///
783 /// - The generated private key is a 256-bit (32-byte) key, which is compatible with the P256 curve used in ECC operations.
784 /// - Ensure that the random bytes are securely generated, as this key will be used in cryptographic operations. The private key should be kept confidential at all times.
785 ///
786 /// # Panics
787 ///
788 /// This function will panic if any of the following conditions occur:
789 /// - The conversion of the URL-safe Base64 string to an integer fails.
790 /// - The `SigningKey` creation from the byte array fails.
791 ///
792 /// # Implementation Details
793 ///
794 /// - The key is derived from random bytes, which are encoded into a URL-safe Base64 string, then decoded back to an integer.
795 /// - The integer is converted to bytes, and the first 16 bytes are used for the key, with the remaining bytes padded with zeros.
796 /// - The final 32-byte array is used to create the `SigningKey` using `SigningKey::from_bytes`.
797 pub fn generate_private_key_ecc() -> Result<SigningKey, KSMRError> {
798 // Generate random bytes for the encryption key
799 let encryption_key_bytes = Self::generate_random_bytes(32);
800
801 // Convert bytes to URL-safe Base64 string
802 let private_key_str = Self::bytes_to_url_safe_str(&encryption_key_bytes);
803
804 // Convert URL-safe Base64 string to integer
805 let encryption_key_int = Self::url_safe_str_to_int(&private_key_str).map_err(|e| {
806 KSMRError::CryptoError(format!(
807 "Failed to convert URL-safe Base64 string to integer: {}",
808 e
809 ))
810 })?;
811
812 // Create a byte array from the integer representation (needs 32 bytes)
813 let mut key_bytes = [0u8; 32];
814
815 // Right-align int_bytes in key_bytes
816 let int_bytes = encryption_key_int.to_bytes_be();
817 let start = 32 - int_bytes.len();
818 key_bytes[start..].copy_from_slice(&int_bytes);
819
820 // Create SigningKey from the byte array
821 SigningKey::from_bytes(GenericArray::from_slice(&key_bytes)).map_err(|e| {
822 KSMRError::CryptoError(format!("Failed to create SigningKey from bytes: {}", e))
823 })?;
824
825 // Return the generated SigningKey
826 Ok(SigningKey::from_bytes(GenericArray::from_slice(&key_bytes)).unwrap())
827 }
828
829 #[allow(clippy::needless_doctest_main)]
830 /// Generates a new ECC private key.
831 ///
832 /// This function generates a new 256-bit (32-byte) private key suitable for ECC operations,
833 /// specifically for the P256 curve. The process involves generating random bytes, converting
834 /// those bytes into a URL-safe Base64 string, and then converting that string into an integer.
835 /// The integer is then used to create the `SigningKey`, which represents the ECC private key.
836 ///
837 /// # Returns
838 ///
839 /// This function returns a `Result`:
840 /// - `Ok(SigningKey)`: The successfully generated ECC private key as a `SigningKey`.
841 /// - `Err(KSMRError)`: An error if any step of the key generation process fails, including random byte generation, Base64 conversion, integer conversion, or `SigningKey` creation.
842 ///
843 /// # Example
844 ///
845 /// ```rust
846 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust to your actual module path
847 ///
848 /// fn main() {
849 /// // Generate a new ECC private key
850 /// let private_key = CryptoUtils::generate_private_key_ecc().unwrap();
851 ///
852 /// // Print or use the private key as needed
853 /// println!("Generated Private Key: {:?}", private_key);
854 /// }
855 /// ```
856 ///
857 /// # Notes
858 ///
859 /// - The generated private key is a 256-bit (32-byte) key, which is compatible with the P256 curve used in ECC operations.
860 /// - The first 16 bytes of the 32-byte private key are filled with the integer representation of the random bytes.
861 /// - The second 16 bytes are a repeat of the same integer to meet the required key length for P256.
862 /// - Ensure that the random bytes are securely generated, as this key will be used in cryptographic operations. The private key should be kept confidential at all times.
863 ///
864 /// # Panics
865 ///
866 /// This function will panic if any of the following conditions occur:
867 /// - The conversion of the URL-safe Base64 string to an integer fails.
868 /// - The `SigningKey` creation from the byte array fails.
869 ///
870 /// # Implementation Details
871 ///
872 /// - The key is derived from random bytes, which are encoded into a URL-safe Base64 string, then decoded back to an integer.
873 /// - The integer is converted to bytes, and the first 16 bytes are used for the key, with the remaining bytes padded with zeros.
874 /// - The final 32-byte array is used to create the `SigningKey` using `SigningKey::from_bytes`.
875 pub fn generate_private_key_der() -> Result<Vec<u8>, KSMRError> {
876 // Generate ECC signing key
877 let signing_key = Self::generate_private_key_ecc()
878 .map_err(|err| KSMRError::CryptoError(err.to_string()))
879 .unwrap();
880
881 // Export to DER format
882 match signing_key.to_pkcs8_der() {
883 Ok(private_key_der) => Ok(private_key_der.as_bytes().to_vec()), // Return the DER bytes
884 Err(e) => Err(KSMRError::CryptoError(format!(
885 "Failed to serialize to DER: {}",
886 e
887 ))),
888 }
889 }
890
891
892
893 #[allow(clippy::needless_doctest_main)]
894 /// Generates a new ephemeral ECC signing key using the SECP256R1 curve.
895 ///
896 /// This function creates a new ECC signing key that can be used for cryptographic operations such as
897 /// signing or key exchange. It utilizes a secure random number generator to ensure the key is
898 /// generated in a cryptographically secure manner.
899 ///
900 /// # Returns
901 ///
902 /// This function returns a `SigningKey`, which represents the newly generated ECC signing key.
903 ///
904 /// # Example
905 ///
906 /// ```rust
907 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust to your actual module path
908 /// use p256::ecdsa::SigningKey;
909 /// fn main() {
910 /// // Generate a new ECC signing key
911 /// let signing_key: SigningKey = CryptoUtils::generate_new_ecc_key();
912 ///
913 /// // Use the signing key for further cryptographic operations
914 /// println!("Generated new ECC signing key: {:?}", signing_key);
915 /// }
916 /// ```
917 ///
918 /// # Notes
919 ///
920 /// - The generated key is ephemeral and should be used for a single session or transaction.
921 /// - Ensure that you securely manage and store the signing key if needed, as it is essential for
922 /// cryptographic integrity.
923 pub fn generate_new_ecc_key() -> SigningKey {
924 // Create a new OS random number generator
925 let mut rng = OsRng;
926
927 // Generate an ephemeral ECC signing key for SECP256R1
928 SigningKey::random(&mut rng)
929 }
930
931 /// Encrypts data using AES-256-GCM with an optional nonce.
932 ///
933 /// This function performs authenticated encryption of the provided `data` using AES-256-GCM.
934 /// AES-256-GCM requires a 32-byte key for encryption and uses a 12-byte nonce. If a nonce is
935 /// not provided, a random 12-byte nonce will be generated.
936 ///
937 /// # Parameters
938 ///
939 /// - `data`: A byte slice representing the plaintext data to be encrypted.
940 /// - `key_bytes`: A byte slice representing the 32-byte AES key used for encryption (AES-256).
941 /// - `nonce_bytes`: An optional byte slice representing the nonce. If not provided, a random nonce will be generated.
942 ///
943 /// # Returns
944 ///
945 /// This function returns a `Result`:
946 /// - `Ok(Vec<u8>)`: The result will contain a vector with the concatenated nonce and the encrypted ciphertext on success.
947 /// - `Err(KSMRError)`: An error if encryption fails or if invalid input parameters are provided (e.g., wrong key size).
948 ///
949 /// # Errors
950 ///
951 /// - Returns `KSMRError::CryptoError("Invalid key size")` if the provided `key_bytes` slice is not exactly 32 bytes long.
952 /// - Returns `KSMRError::CryptoError("Encryption failed")` if the encryption operation fails (for example, due to invalid key or data).
953 ///
954 /// # Example
955 ///
956 /// ```rust
957 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
958 /// use std::error::Error;
959 /// use hex;
960 ///
961 /// fn main() -> Result<(), Box<dyn Error>> {
962 /// // 32-byte AES key (AES-256 requires a 32-byte key)
963 /// let key = b"an example very very secret key."; // Must be exactly 32 bytes
964 ///
965 /// // Example plaintext data
966 /// let data = b"plaintext message that needs encryption";
967 ///
968 /// // Encrypt the data with a random nonce
969 /// let encrypted_data = CryptoUtils::encrypt_aes_gcm(data, key, None)?;
970 ///
971 /// // Print the encrypted data in hex format for better readability
972 /// println!("Encrypted data: {:?}", hex::encode(&encrypted_data));
973 ///
974 /// Ok(())
975 /// }
976 /// ```
977 ///
978 /// # Panics
979 ///
980 /// This function does not panic under normal operation. However, it will return an error if input is invalid (e.g., wrong key size or if encryption fails).
981 ///
982 /// # Notes
983 ///
984 /// - AES-256-GCM is an authenticated encryption mode, which provides both confidentiality and integrity. The nonce should be unique for each encryption operation with the same key to maintain security.
985 /// - The nonce is prepended to the ciphertext before returning, allowing the recipient to extract and use it for decryption.
986 ///
987 /// # Implementation Details
988 ///
989 /// - AES-256-GCM requires a 32-byte key, and the nonce used must be 12 bytes in length. If a nonce is not provided, a random 12-byte nonce will be generated for each encryption operation.
990 /// - The AES-GCM encryption process uses the provided key and nonce to encrypt the `data`. The resulting ciphertext is then concatenated with the nonce before being returned.
991 /// - The function uses the `Aes256Gcm` cipher from the `aes-gcm` crate and the `rand` crate to generate random nonces when necessary.
992 pub fn encrypt_aes_gcm(
993 data: &[u8],
994 key_bytes: &[u8],
995 nonce_bytes: Option<&[u8]>,
996 ) -> Result<Vec<u8>, KSMRError> {
997 let _ = nonce_bytes;
998
999 // Validate key size (32 bytes for AES-256)
1000 if key_bytes.len() != 32 {
1001 return Err(KSMRError::CryptoError("Invalid key size".to_string()));
1002 }
1003
1004 if key_bytes.len() != 32 {
1005 return Err(KSMRError::CryptoError("Invalid key size".to_string()));
1006 }
1007
1008 // Create the key from the provided bytes
1009 let mut cipher_obj =
1010 aes_gcm::Aes256Gcm::new(aes_gcm::Key::<Aes256Gcm>::from_slice(key_bytes));
1011 let nonce_obj = aes_gcm::Aes256Gcm::generate_nonce(&mut OsRng);
1012 let cipher_txt_obj = cipher_obj
1013 .encrypt(&nonce_obj, data)
1014 .map_err(|_| KSMRError::CryptoError("Encryption failed".to_string()))?;
1015
1016 let mut result_obj = Vec::with_capacity(nonce_obj.as_slice().len() + cipher_txt_obj.len());
1017 result_obj.extend_from_slice(nonce_obj.as_slice());
1018 result_obj.extend_from_slice(&cipher_txt_obj);
1019 Ok(result_obj)
1020 }
1021
1022 /// Decrypts data using AES-256-GCM with a 12-byte nonce.
1023 ///
1024 /// # Parameters
1025 ///
1026 /// - `data`: A byte slice containing the nonce followed by the ciphertext. The first 12 bytes represent the nonce, and the rest is the ciphertext.
1027 /// - `key_bytes`: A byte slice representing the 32-byte AES key used for decryption (AES-256).
1028 ///
1029 /// # Returns
1030 ///
1031 /// This function returns a `Result`:
1032 /// - `Ok(Vec<u8>)`: The decrypted plaintext on success.
1033 /// - `Err(Box<dyn Error>)`: An error if decryption fails or if invalid input parameters are provided (e.g., wrong key size).
1034 ///
1035 /// # Errors
1036 ///
1037 /// - Returns `"Invalid key size"` if the provided `key_bytes` slice is not exactly 32 bytes long.
1038 /// - Returns `"Data too short to contain nonce"` if the provided `data` slice is smaller than 12 bytes.
1039 /// - Returns `"Decryption failed"` if the decryption operation itself fails (for example, if the ciphertext or key is invalid).
1040 ///
1041 /// # Example
1042 ///
1043 /// ```rust
1044 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1045 /// use keeper_secrets_manager_core::custom_error::KSMRError;
1046 /// use aes_gcm::{Aes256Gcm, Key, Nonce}; // Import the AES-GCM library
1047 /// use std::error::Error;
1048 /// use hex;
1049 ///
1050 /// fn main() -> Result<(), KSMRError> {
1051 /// // 32-byte AES key (AES-256 requires a 32-byte key)
1052 /// let key = b"an example very very secret key."; // Should be exactly 32 bytes
1053 ///
1054 /// // 12-byte nonce (unique for each encryption)
1055 /// let nonce = b"unique nonce"; // Must be exactly 12 bytes
1056 ///
1057 /// // Example ciphertext (encrypted using the same key and nonce)
1058 /// let ciphertext = hex::decode("c5d3db06f6c3d543663a94051a7a0d65")?; // Example encrypted data
1059 ///
1060 /// // Concatenate nonce and ciphertext
1061 /// let mut encrypted_data = Vec::new();
1062 /// encrypted_data.extend_from_slice(nonce);
1063 /// encrypted_data.extend_from_slice(&ciphertext);
1064 ///
1065 /// // Attempt to decrypt the data
1066 /// let result = CryptoUtils::decrypt_aes(&encrypted_data, key);
1067 ///
1068 /// // Check if the decryption was successful
1069 /// match result {
1070 /// Ok(decrypted_data) => {
1071 /// println!("Decrypted data: {:?}", decrypted_data);
1072 /// },
1073 /// Err(err) => {
1074 /// println!("Error: {}", err);
1075 /// assert_eq!(err.to_string(), "Cryptography module Error: aead::Error");
1076 /// }
1077 /// }
1078 ///
1079 /// Ok(())
1080 /// }
1081 /// ```
1082 ///
1083 /// # Panics
1084 ///
1085 /// This function does not panic under normal operation. However, it will return an error if input is invalid (e.g., wrong key size or if decryption fails).
1086 ///
1087 /// # Notes
1088 ///
1089 /// - This function assumes that the first 12 bytes of `data` represent the nonce.
1090 /// - AES-256-GCM is an authenticated encryption mode, so decryption will fail if the ciphertext or key is tampered with.
1091 pub fn decrypt_aes(data: &[u8], key_bytes: &[u8]) -> Result<Vec<u8>, KSMRError> {
1092 use aes_gcm::KeyInit;
1093 // Validate key size (32 bytes for AES-256)
1094 if key_bytes.len() != 32 {
1095 return Err(KSMRError::CryptoError("Invalid key size".to_string()));
1096 }
1097
1098 if data.len() < 12 {
1099 return Err(KSMRError::CryptoError(
1100 "Data too short to contain nonce".to_string(),
1101 ));
1102 }
1103
1104 let ciphertext = &data[12..]; // The rest is the ciphertext
1105
1106 let mut key2 = aes_gcm::Aes256Gcm::new_from_slice(key_bytes)
1107 .map_err(|err| KSMRError::CryptoError(err.to_string()))?;
1108 let nonce2 = aes_gcm::Nonce::from_slice(&data[..12]);
1109
1110 // Decrypt the data
1111 let decrypted_plaintext = key2
1112 .decrypt(nonce2, ciphertext)
1113 .map_err(|err| KSMRError::CryptoError(err.to_string()))?;
1114 Ok(decrypted_plaintext)
1115 }
1116
1117 /// Encrypts data using AES-256 in CBC (Cipher Block Chaining) mode.
1118 ///
1119 /// This function encrypts the provided plaintext data using AES-256 in CBC mode with a 32-byte key.
1120 /// If an Initialization Vector (IV) is not provided, a random 16-byte IV is generated. The IV
1121 /// is then prepended to the resulting ciphertext for later use during decryption.
1122 ///
1123 /// # Parameters
1124 ///
1125 /// - `data`: A byte slice representing the plaintext data to be encrypted.
1126 /// - `key`: A 32-byte slice representing the AES-256 key used for encryption (AES-256 requires a 256-bit key).
1127 /// - `iv`: An optional 16-byte slice representing the Initialization Vector (IV). If `None` is provided,
1128 /// a random IV will be generated.
1129 ///
1130 /// # Returns
1131 ///
1132 /// This function returns a `Result`:
1133 /// - `Ok(Vec<u8>)`: A vector containing the concatenated IV and the encrypted ciphertext on success.
1134 /// - `Err(KSMRError)`: An error if the key size is invalid (i.e., not 32 bytes).
1135 ///
1136 /// # Errors
1137 ///
1138 /// - Returns `KSMRError::CryptoError("Invalid key size")` if the provided `key` is not 32 bytes long.
1139 /// - Returns an error if encryption fails or if the padding or encryption process encounters issues.
1140 ///
1141 /// # Example
1142 ///
1143 /// ```rust
1144 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1145 /// use rand::rngs::OsRng;
1146 ///
1147 /// let plaintext = b"Sensitive data to encrypt";
1148 /// let key = b"0123456789abcdef0123456789abcdef"; // A 32-byte AES-256 key.
1149 /// let iv = b"1234567890123456"; // A 16-byte IV (optional).
1150 ///
1151 /// let encrypted_data = CryptoUtils::encrypt_aes_cbc(plaintext, key, Some(iv)).unwrap();
1152 ///
1153 /// println!("Encrypted data: {:?}", encrypted_data);
1154 /// ```
1155 ///
1156 /// # Panics
1157 ///
1158 /// This function does not panic but returns an error if input is invalid (e.g., incorrect key size or encryption failure).
1159 ///
1160 /// # Notes
1161 ///
1162 /// - AES-256 in CBC mode requires the key to be exactly 32 bytes. The IV must be 16 bytes in length.
1163 /// - CBC mode requires padding to ensure the data is a multiple of the block size (16 bytes for AES). This function uses a padding scheme (assumed to be implemented in `pad_data`) to handle this.
1164 /// - The resulting ciphertext is returned with the IV prepended to facilitate decryption.
1165 pub fn encrypt_aes_cbc(
1166 data: &[u8],
1167 key: &[u8],
1168 iv: Option<&[u8]>,
1169 ) -> Result<Vec<u8>, KSMRError> {
1170 if key.len() != AES_256_KEY_SIZE {
1171 return Err(KSMRError::CryptoError("Invalid key size".to_string()));
1172 }
1173
1174 let iv = match iv {
1175 Some(iv) => iv.to_vec(),
1176 None => {
1177 let mut iv = vec![0u8; BLOCK_SIZE];
1178 OsRng.fill_bytes(&mut iv); // Secure random IV generation
1179 iv
1180 }
1181 };
1182
1183 match iv.len() {
1184 BLOCK_SIZE => (),
1185 _ => {
1186 return Err(KSMRError::CryptoError("Invalid IV size".to_string()));
1187 }
1188 }
1189
1190 let cipher = Aes256::new(GenericArray::from_slice(key));
1191 let padded_data = pad_data(data, BLOCK_SIZE);
1192 let mut ciphertext = Vec::with_capacity(padded_data.len());
1193 let mut previous_block = iv.clone();
1194
1195 for block in padded_data.chunks(BLOCK_SIZE) {
1196 let mut block = block.to_vec();
1197
1198 // XOR block with the previous block or IV
1199 for (i, byte) in block.iter_mut().enumerate() {
1200 *byte ^= previous_block[i];
1201 }
1202
1203 let mut block_arr = GenericArray::clone_from_slice(&block);
1204 cipher.encrypt_block(&mut block_arr);
1205
1206 ciphertext.extend_from_slice(&block_arr);
1207 previous_block = block_arr.to_vec();
1208 }
1209
1210 let mut result = iv.clone();
1211 result.extend(ciphertext);
1212 Ok(result)
1213 }
1214
1215 /// Decrypts data using AES-256 in CBC (Cipher Block Chaining) mode.
1216 ///
1217 /// This function decrypts the provided encrypted data using AES-256 in CBC mode with a 32-byte key.
1218 /// The first 16 bytes of the input data are treated as the Initialization Vector (IV), and the remaining
1219 /// bytes are treated as the ciphertext. After decryption, the padding is removed from the data to obtain the
1220 /// original plaintext.
1221 ///
1222 /// # Parameters
1223 ///
1224 /// - `data`: A byte slice representing the encrypted data. The first 16 bytes are treated as the IV, and the
1225 /// remaining bytes are the ciphertext.
1226 /// - `key`: A 32-byte slice representing the AES-256 key used for decryption.
1227 ///
1228 /// # Returns
1229 ///
1230 /// This function returns a `Result`:
1231 /// - `Ok(Vec<u8>)`: A vector containing the decrypted and unpadded plaintext data.
1232 /// - `Err(KSMRError)`: An error if the key size is invalid, the data is too short to contain an IV, or the
1233 /// data length is not a multiple of 16 bytes (indicating possible encoding issues).
1234 ///
1235 /// # Errors
1236 ///
1237 /// - Returns `KSMRError::CryptoError("Invalid key size")` if the provided `key` is not 32 bytes long.
1238 /// - Returns `KSMRError::CryptoError("Data too short to contain IV")` if the provided `data` is less than 16 bytes long.
1239 /// - Returns `KSMRError::CryptoError("Data is probably not encoded")` if the data length is not a multiple of 16 bytes.
1240 /// - Returns `KSMRError::CryptoError("Unpadding failed: <error message>")` if the unpadding process fails.
1241 ///
1242 /// # Example
1243 ///
1244 /// ```rust
1245 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1246 ///
1247 /// let encrypted_data = b"\x01\x02..."; // Some encrypted data with a 16-byte IV followed by ciphertext.
1248 /// let key = b"0123456789abcdef0123456789abcdef"; // A 32-byte AES-256 key.
1249 /// let data = CryptoUtils::decrypt_aes_cbc(encrypted_data, key);
1250 /// match data {
1251 /// Ok(plaintext) => println!("Decrypted data: {:?}", plaintext),
1252 /// Err(e) => eprintln!("Decryption error: {}", e),
1253 /// }
1254 /// ```
1255 ///
1256 /// In this example, `decrypt_aes_cbc` attempts to decrypt the `encrypted_data` using the provided AES-256 key.
1257 /// The decrypted data is returned after removing the padding.
1258 ///
1259 /// # Panics
1260 ///
1261 /// This function does not panic but returns a `Result` in case of errors.
1262 ///
1263 /// # Notes
1264 ///
1265 /// - AES-256 in CBC mode requires the key to be exactly 32 bytes. The IV must be 16 bytes in length.
1266 /// - The first 16 bytes of the input data are interpreted as the IV, while the rest is treated as the ciphertext.
1267 /// - CBC mode requires the ciphertext length to be a multiple of the AES block size (16 bytes).
1268 /// - The padding is removed from the decrypted data using a custom unpadding function (`unpad_data`), which will return an error if the padding is incorrect.
1269 pub fn decrypt_aes_cbc(data: &[u8], key: &[u8]) -> Result<Vec<u8>, KSMRError> {
1270 // Validate key size (32 bytes for AES-256)
1271 if key.len() != 32 {
1272 return Err(KSMRError::CryptoError("Invalid key size".to_string()));
1273 }
1274 // Validate that data is large enough to contain an IV (16 bytes for AES-CBC)
1275 if data.len() < 16 {
1276 return Err(KSMRError::CryptoError(
1277 "Data too short to contain IV".to_string(),
1278 ));
1279 }
1280 // Extract the IV and ciphertext
1281 let iv = &data[..16]; // First 16 bytes are the IV
1282 let ciphertext = &data[16..]; // Remaining bytes are the encrypted data
1283 // Validate ciphertext length
1284 if ciphertext.len() % BLOCK_SIZE != 0 {
1285 return Err(KSMRError::CryptoError("Data is probably not encoded".to_string()));
1286 }
1287 let cipher = Aes256::new(GenericArray::from_slice(key));
1288 let mut plaintext = Vec::with_capacity(ciphertext.len());
1289 let mut previous_block = iv.to_vec();
1290 for block in ciphertext.chunks(BLOCK_SIZE) {
1291 let mut block_arr = GenericArray::clone_from_slice(block);
1292 cipher.decrypt_block(&mut block_arr);
1293 // XOR decrypted block with previous ciphertext block (or IV)
1294 let decrypted_block: Vec<u8> = block_arr
1295 .iter()
1296 .zip(&previous_block)
1297 .map(|(b, p)| b ^ p)
1298 .collect();
1299 plaintext.extend_from_slice(&decrypted_block);
1300 previous_block = block.to_vec();
1301 }
1302 // Remove PKCS#7 padding
1303 // let unpadded = unpad_data(&plaintext)
1304 // .map_err(|e| KSMRError::CryptoError(format!("Unpadding failed: {}", e)))?;
1305 Ok(plaintext)
1306 }
1307
1308 /// Encrypts data using an ephemeral ECDH key exchange and AES-GCM.
1309 ///
1310 /// This function uses Elliptic Curve Diffie-Hellman (ECDH) to derive a shared secret between
1311 /// an ephemeral key generated on the fly and a server's public key provided in the input.
1312 /// The derived key is optionally concatenated with an identifier (`idz`), hashed using SHA-256
1313 /// to generate an AES encryption key, and then used to encrypt the input data with AES-GCM.
1314 ///
1315 /// # Arguments
1316 ///
1317 /// * `data` - A byte slice representing the data to be encrypted.
1318 /// * `server_public_raw_key_bytes` - A byte slice representing the server's public key in SEC1 format.
1319 /// * `idz` - An optional byte slice identifier that, if provided, is appended to the shared secret before key derivation.
1320 ///
1321 /// # Returns
1322 ///
1323 /// This function returns a `Result` containing:
1324 /// - `Ok(Vec<u8>)`: A vector of bytes containing the concatenation of the ephemeral public key and the encrypted data.
1325 /// - `Err(KSMRError)`: An error if key derivation or encryption fails.
1326 ///
1327 /// # Errors
1328 ///
1329 /// * Returns an error if the server public key is invalid or encryption fails.
1330 /// * If the `server_public_raw_key_bytes` cannot be parsed into a valid public key, it returns `"Invalid server public key!"`.
1331 /// * If encryption fails during AES-GCM, the error message will indicate the failure.
1332 ///
1333 /// # Example
1334 ///
1335 /// ```rust
1336 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1337 ///
1338 /// // Data to encrypt
1339 /// let data = b"Sensitive data to encrypt";
1340 ///
1341 /// // A raw public key as a string (this is just an example key)
1342 /// let server_public_key = "04d88c6fa31ea40af14c137b8e62f1151f1cc1e5688cad37b7f2e7";
1343 ///
1344 /// // Convert the public key from hex string to bytes
1345 /// let server_public_key_bytes = hex::decode(server_public_key).expect("Invalid hex key");
1346 ///
1347 /// // Optional IDZ
1348 /// let idz = Some("optional_identifier".as_bytes());
1349 ///
1350 /// // Encrypt the data
1351 /// match CryptoUtils::public_encrypt(data, &server_public_key_bytes, idz) {
1352 /// Ok(encrypted_data) => println!("Encrypted data: {:?}", encrypted_data),
1353 /// Err(e) => println!("Encryption failed: {}", e),
1354 /// }
1355 /// ```
1356 pub fn public_encrypt(
1357 data: &[u8],
1358 server_public_raw_key_bytes: &[u8],
1359 idz: Option<&[u8]>,
1360 ) -> Result<Vec<u8>, KSMRError> {
1361 // Load the server public key from raw bytes
1362 let server_public_key = PublicKey::from_sec1_bytes(server_public_raw_key_bytes)
1363 .map_err(|_| KSMRError::CryptoError("Invalid server public key!".to_string()))?;
1364
1365 // Generate a new ephemeral key
1366 let ephemeral_key = EphemeralSecret::random(&mut OsRng);
1367
1368 // Compute the shared key using ECDH (Diffie-Hellman)
1369 let shared_key = ephemeral_key.diffie_hellman(&server_public_key);
1370
1371 // If idz is provided, concatenate it with the shared secret
1372 let mut derived_key = shared_key.raw_secret_bytes().to_vec();
1373 if let Some(idz_bytes) = idz {
1374 derived_key.extend_from_slice(idz_bytes);
1375 }
1376
1377 // Hash the derived key to create a suitable AES key
1378 let mut hasher = sha2::Sha256::new();
1379 hasher.update(&derived_key);
1380 let enc_key = hasher.finalize().to_vec();
1381
1382 // Encrypt the data with AES-GCM
1383 let encrypted_data = CryptoUtils::encrypt_aes_gcm(data, &enc_key, None)
1384 .map_err(|e| KSMRError::CryptoError(format!("AES encryption failed: {}", e)))?;
1385
1386 // Get the public key bytes from the ephemeral key
1387 let eph_key_clone: p256::elliptic_curve::PublicKey<p256::NistP256> =
1388 ephemeral_key.public_key();
1389
1390 let binding_clone = EncodedPoint::from(eph_key_clone);
1391 let eph_public_key_bytes: &[u8] = binding_clone.as_bytes();
1392
1393 // Combine the ephemeral public key and the encrypted data
1394 let mut result = Vec::with_capacity(eph_public_key_bytes.len() + encrypted_data.len());
1395 result.extend_from_slice(eph_public_key_bytes.as_ref());
1396 result.extend_from_slice(&encrypted_data);
1397
1398 Ok(result)
1399 }
1400
1401 /// Computes the SHA-256 hash of a Base64-encoded string.
1402 ///
1403 /// This function takes a Base64-encoded string, decodes it into bytes,
1404 /// and computes its SHA-256 hash. The resulting hash is returned as a
1405 /// vector of bytes.
1406 ///
1407 /// # Arguments
1408 ///
1409 /// * `value` - A string slice representing the Base64-encoded input to hash.
1410 ///
1411 /// # Returns
1412 ///
1413 /// This function returns a `Result`:
1414 /// - `Ok(Vec<u8>)`: The SHA-256 hash of the decoded input as a vector of bytes.
1415 /// - `Err(KSMRError)`: An error if the input string cannot be decoded from Base64
1416 /// or if any other error occurs during hashing.
1417 ///
1418 /// # Errors
1419 ///
1420 /// - Returns `KSMRError::CryptoError` if the input string cannot be decoded from Base64
1421 /// or if any other error occurs during hashing.
1422 ///
1423 /// # Examples
1424 ///
1425 /// ```
1426 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1427 /// let base64_input = "SGVsbG8sIHdvcmxkIQ=="; // Base64 encoding of "Hello, world!"
1428 /// let hash = CryptoUtils::hash_of_string(base64_input);
1429 /// match hash {
1430 /// Ok(h) => println!("SHA-256 Hash: {:?}", h),
1431 /// Err(e) => eprintln!("Error: {}", e),
1432 /// }
1433 /// ```
1434 ///
1435 /// # Panics
1436 ///
1437 /// This function does not panic. It will return a `KSMRError` if the input is not valid Base64
1438 /// or if hashing fails.
1439 pub fn hash_of_string(value: &str) -> Result<Vec<u8>, KSMRError> {
1440 // Decode the Base64-encoded string into bytes
1441 let value_bytes = URL_SAFE_NO_PAD
1442 .decode(value)
1443 .map_err(|e| KSMRError::CryptoError(format!("Base64 decoding failed: {}", e)))?;
1444
1445 // Use sha2 crate for SHA-256 hashing
1446 let mut hasher = sha2::Sha256::new();
1447 hasher.update(&value_bytes);
1448 let hash_result = hasher.finalize();
1449
1450 Ok(hash_result.to_vec())
1451 }
1452
1453 pub fn ecies_decrypt(
1454 _server_public_key: &[u8],
1455 _ciphertext: &[u8],
1456 _priv_key_data: &[u8],
1457 _id: &[u8],
1458 ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1459 unimplemented!("The hashing functionality is not yet implemented.");
1460 }
1461
1462 /// Decrypts a record using the provided secret key.
1463 ///
1464 /// This function attempts to decrypt a given record. If the record is a valid UTF-8 string,
1465 /// it is first decoded from Base64. The decoded bytes are then decrypted using AES-GCM.
1466 /// If the record is not a valid UTF-8 string, it is assumed to be in bytes and is decrypted
1467 /// directly.
1468 ///
1469 /// # Arguments
1470 ///
1471 /// * `data` - A slice of bytes representing the encrypted record. This can either be a
1472 /// Base64-encoded UTF-8 string or raw bytes.
1473 /// * `secret_key` - A slice of bytes representing the secret key used for decryption.
1474 ///
1475 /// # Returns
1476 ///
1477 /// This function returns a `Result<String, KSMRError>`. On success, it returns the
1478 /// decrypted record as a UTF-8 string. On failure, it returns an error with a description
1479 /// of the problem encountered.
1480 ///
1481 /// # Errors
1482 ///
1483 /// This function will return an error if:
1484 /// * The input data cannot be decoded from Base64, returning a `KSMRError::CryptoError` with
1485 /// the description `"Base64 decode error: {error}"`.
1486 /// * The decryption process fails due to an incorrect key or other issues, returning a
1487 /// `KSMRError::CryptoError` with a relevant message.
1488 /// * The resulting decrypted bytes cannot be converted to a UTF-8 string, returning a
1489 /// `KSMRError::Utf8Error` with a description of the error.
1490 ///
1491 /// # Examples
1492 ///
1493 /// ```rust
1494 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1495 /// use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
1496 /// let secret_key = CryptoUtils::generate_random_bytes(32); // Generate a dummy secret key
1497 /// let original_data = b"Hello, World!";
1498 /// let encrypted_data = CryptoUtils::encrypt_aes_gcm(original_data, &secret_key, None).unwrap();
1499 /// let base64_encoded = URL_SAFE_NO_PAD.encode(&encrypted_data);
1500 /// // Action
1501 /// let result = CryptoUtils::decrypt_record(base64_encoded.as_bytes(), &secret_key);
1502 /// // Assert
1503 /// assert_eq!(result.unwrap(), "Hello, World!");
1504 ///
1505 /// let result2 = CryptoUtils::decrypt_record(base64_encoded.as_bytes(), &secret_key);
1506 /// match result2 {
1507 /// Ok(record) => println!("Decrypted record: {}", record),
1508 /// Err(e) => eprintln!("Failed to decrypt record: {}", e),
1509 /// }
1510 /// ```
1511 ///
1512 /// # Panics
1513 ///
1514 /// This function does not panic under normal circumstances. It handles errors by returning a `KSMRError`.
1515 pub fn decrypt_record(data: &[u8], secret_key: &[u8]) -> Result<String, KSMRError> {
1516 let decrypted_data = if let Ok(s) = std::str::from_utf8(data) {
1517 // If the data is a valid UTF-8 string, decode from Base64
1518 let decoded_bytes = URL_SAFE_NO_PAD
1519 .decode(s)
1520 .map_err(|e| KSMRError::CryptoError(format!("Base64 decode error: {}", e)))?;
1521 // Decrypt the decoded bytes
1522 CryptoUtils::decrypt_aes(&decoded_bytes, secret_key)
1523 .map_err(|e| KSMRError::CryptoError(format!("AES decryption error: {}", e)))?
1524 } else {
1525 // If the data is not a valid UTF-8 string, assume it's already in bytes
1526 CryptoUtils::decrypt_aes(data, secret_key)
1527 .map_err(|e| KSMRError::CryptoError(format!("AES decryption error: {}", e)))?
1528 };
1529
1530 // Convert decrypted bytes to a UTF-8 string
1531 let record_json = String::from_utf8(decrypted_data)
1532 .map_err(|e| KSMRError::CryptoError(format!("UTF-8 conversion error: {}", e)))?;
1533 Ok(record_json)
1534 }
1535
1536 pub fn decrypt_ec(
1537 _ecc_private_key: &SecretKey,
1538 _encrypted_data_bag: &[u8],
1539 ) -> Result<Vec<u8>, Box<dyn Error>> {
1540 unimplemented!("The hashing functionality is not yet implemented.");
1541 }
1542
1543 /// Converts a Base64-encoded DER private key string to a `SecretKey`.
1544 ///
1545 /// This function takes a Base64-encoded DER representation of a private key,
1546 /// decodes it, and converts it into a `SecretKey` type suitable for cryptographic
1547 /// operations.
1548 ///
1549 /// # Arguments
1550 ///
1551 /// * `private_key_der_base64` - A string slice containing the Base64-encoded
1552 /// DER representation of the private key.
1553 ///
1554 /// # Returns
1555 ///
1556 /// This function returns a `Result<p256::SecretKey, KSMRError>`. On success,
1557 /// it returns the corresponding `SecretKey`. On failure, it returns an error with a
1558 /// description of the problem encountered.
1559 ///
1560 /// # Errors
1561 ///
1562 /// This function will return an error if:
1563 /// * The provided Base64 string cannot be decoded. The error will be wrapped in a `KSMRError::CryptoError`.
1564 /// * The decoded bytes cannot be parsed into a `SecretKey`. The error will be wrapped in a `KSMRError::CryptoError`.
1565 ///
1566 /// # Examples
1567 ///
1568 /// ```rust
1569 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust the path as necessary
1570 /// use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
1571 /// use p256::SecretKey; // Import the SecretKey type
1572 ///
1573 /// let private_key_der_base64 = "your_base64_encoded_der_key_here"; // Replace with your Base64 DER key
1574 ///
1575 /// // Attempt to convert the Base64 DER private key to a SecretKey
1576 /// match CryptoUtils::der_base64_private_key_to_private_key(private_key_der_base64) {
1577 /// Ok(secret_key) => println!("Successfully converted to SecretKey: {:?}", secret_key),
1578 /// Err(e) => eprintln!("Failed to convert private key: {}", e),
1579 /// }
1580 /// ```
1581 ///
1582 /// # Panics
1583 ///
1584 /// This function does not panic under normal circumstances, but it may return an
1585 /// error if the input is invalid.
1586 pub fn der_base64_private_key_to_private_key(
1587 private_key_der_base64: &str,
1588 ) -> Result<
1589 SecretKey,
1590 // EcKey<openssl::pkey::Private> ,
1591 KSMRError,
1592 > {
1593 use p256::pkcs8::DecodePrivateKey;
1594 // Decode the Base64-encoded DER string
1595 let private_key_der_bytes = utils::base64_to_bytes(private_key_der_base64)?;
1596
1597 // Convert to SecretKey
1598 let private_key = SecretKey::from_pkcs8_der(&private_key_der_bytes).map_err(|e| {
1599 KSMRError::CryptoError(format!("Failed to convert DER to SecretKey: {}", e))
1600 })?;
1601
1602 Ok(private_key)
1603 }
1604
1605 /// Extracts the public key bytes from a Base64-encoded DER private key string.
1606 ///
1607 /// This function takes a Base64-encoded DER representation of a private key,
1608 /// decodes it, and extracts the corresponding public key bytes in uncompressed format.
1609 ///
1610 /// # Arguments
1611 ///
1612 /// * `private_key_der_base64` - A string slice containing the Base64-encoded DER private key.
1613 ///
1614 /// # Returns
1615 ///
1616 /// Returns a `Result<Vec<u8>, KSMRError>`. On success, it returns the public key bytes
1617 /// in uncompressed format. On failure, it returns a `KSMRError` with a description of the problem.
1618 ///
1619 /// # Errors
1620 ///
1621 /// This function will return an error if:
1622 /// * The provided Base64 string cannot be decoded.
1623 /// * The decoded bytes cannot be parsed into a `SecretKey`.
1624 ///
1625 /// # Examples
1626 ///
1627 /// ```
1628 /// use keeper_secrets_manager_core::crypto::CryptoUtils;
1629 /// use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _};
1630 ///
1631 /// let private_key_der_base64 = "your_base64_encoded_der_key_here"; // Replace with your Base64 DER key
1632 ///
1633 /// // Attempt to extract public key bytes
1634 /// match CryptoUtils::extract_public_key_bytes(private_key_der_base64) {
1635 /// Ok(public_key_bytes) => println!("Successfully extracted public key bytes: {:?}", public_key_bytes),
1636 /// Err(e) => eprintln!("Failed to extract public key bytes: {}", e),
1637 /// }
1638 /// ```
1639 ///
1640 /// # Panics
1641 ///
1642 /// This function does not panic under normal circumstances, but it will return an error if
1643 /// the Base64 string is invalid or the private key cannot be parsed.
1644 pub fn extract_public_key_bytes(private_key_der_base64: &str) -> Result<Vec<u8>, KSMRError> {
1645 // Decode the Base64-encoded DER string
1646 let private_key_der_bytes = utils::base64_to_bytes(private_key_der_base64)?;
1647
1648 // Convert to SecretKey
1649 let private_key = SecretKey::from_pkcs8_der(&private_key_der_bytes)
1650 .map_err(|e| KSMRError::CryptoError(format!("Failed to load private key: {}", e)))?;
1651
1652 // Derive the public key from the private key
1653 let public_key: VerifyingKey = private_key.public_key().into();
1654
1655 // Convert public key to bytes
1656 let pub_key_bytes = public_key.to_encoded_point(false).as_ref().to_vec();
1657
1658 Ok(pub_key_bytes)
1659 }
1660
1661 /// Signs the provided data using the specified private key.
1662 ///
1663 /// This function takes a byte slice representing the data to be signed and a
1664 /// `SecretKey`. It creates a signing key from the private key and uses it
1665 /// to generate a digital signature for the data.
1666 ///
1667 /// # Arguments
1668 ///
1669 /// * `data` - A slice of bytes representing the data to be signed.
1670 /// * `private_key` - A reference to the `SecretKey` used to sign the data.
1671 ///
1672 /// # Returns
1673 ///
1674 /// This function returns a `Result<Signature, Box<dyn std::error::Error>>`. On success,
1675 /// it returns the generated `Signature`. On failure, it returns an error with a
1676 /// description of the problem encountered.
1677 ///
1678 /// # Errors
1679 ///
1680 /// This function may return an error if:
1681 /// * The signing process fails due to an invalid private key or other cryptographic issues.
1682 ///
1683 /// # Examples
1684 ///
1685 /// ```
1686 /// use keeper_secrets_manager_core::crypto::CryptoUtils; // Adjust the path as necessary
1687 /// use p256::{SecretKey, ecdsa::{SigningKey, Signature}}; // Import necessary types
1688 /// use rand::rngs::OsRng; // Use OS random number generator
1689 ///
1690 /// // Generate a dummy private key
1691 /// let private_key = SecretKey::random(&mut OsRng);
1692 /// let data = b"Hello, World!"; // Data to be signed
1693 ///
1694 /// // Attempt to sign the data
1695 /// match CryptoUtils::sign_data(data, private_key) {
1696 /// Ok(signature) => println!("Successfully signed the data: {:?}", signature),
1697 /// Err(e) => eprintln!("Failed to sign the data: {}", e),
1698 /// }
1699 /// ```
1700 ///
1701 /// # Panics
1702 ///
1703 /// This function does not panic under normal circumstances, but it may return an
1704 /// error if the signing process encounters issues.
1705 pub fn sign_data(
1706 data: &[u8],
1707 // private_key: EcKey<openssl::pkey::Private>
1708 private_key: SecretKey,
1709 ) -> Result<
1710 // Signature,
1711 ecdsa::der::Signature<p256::NistP256>,
1712 KSMRError,
1713 > {
1714 // Create a SigningKey from the SecretKey
1715 let signing_key: ecdsa::SigningKey<p256::NistP256> = SigningKey::from(private_key);
1716 let signature: Signature = signing_key.sign(data);
1717 Ok(signature.to_der())
1718 }
1719
1720 pub fn validate_signature(
1721 data: &[u8], // The original data that was signed
1722 signature_bytes: &[u8], // The signature in DER format
1723 public_key_bytes: &[u8], // The public key in uncompressed form
1724 ) -> Result<bool, KSMRError> {
1725 // Create a VerifyingKey from the public key bytes
1726 let public_key = VerifyingKey::from_sec1_bytes(public_key_bytes).map_err(|err| {
1727 KSMRError::CryptoError(format!(
1728 "Failed to load public key from sec1 bytes: {}",
1729 err
1730 ))
1731 })?;
1732
1733 // Parse the signature from bytes
1734 let signature = Signature::from_der(signature_bytes).map_err(|err| {
1735 KSMRError::CryptoError(format!(
1736 "Failed to parse signature from der while verification: {}",
1737 err
1738 ))
1739 })?;
1740
1741 // Verify the signature using the public key and data
1742 public_key.verify(data, &signature).map_err(|err| {
1743 KSMRError::CryptoError(format!("Failed to verify signature: {}", err))
1744 })?;
1745
1746 // If verification passes, return true
1747 Ok(true)
1748 }
1749}