1use core::fmt;
6
7#[cfg(feature = "alloc")]
8extern crate alloc;
9#[cfg(feature = "alloc")]
10#[allow(unused_imports)]
11use alloc::{
12 string::{
13 String,
14 ToString,
15 },
16 vec::Vec,
17};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum HexDecodeError {
23 OddLength {
25 char_count: usize,
27 },
28 InvalidDigit {
30 pair_start: usize,
32 char_count: usize,
34 },
35}
36
37impl fmt::Display for HexDecodeError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 HexDecodeError::OddLength { char_count } => write!(
41 f,
42 "odd hex length ({char_count} characters); length must be even"
43 ),
44 HexDecodeError::InvalidDigit {
45 pair_start,
46 char_count,
47 } => write!(
48 f,
49 "invalid hex digit at index {pair_start} (trimmed length {char_count})"
50 ),
51 }
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub enum Error {
66 InvalidKeySize { expected: usize, actual: usize },
72
73 InvalidSignatureSize { expected: usize, actual: usize },
79
80 InvalidNonceSize { expected: usize, actual: usize },
86
87 InvalidMessageSize { max: usize, actual: usize },
96
97 InvalidCiphertextSize { expected: usize, actual: usize },
103
104 InvalidPlaintextSize { expected: usize, actual: usize },
110
111 InvalidAssociatedDataSize { max: usize, actual: usize },
117
118 InvalidTagSize { expected: usize, actual: usize },
124
125 InvalidHashSize { expected: usize, actual: usize },
131
132 InvalidAlgorithm { algorithm: &'static str },
138
139 #[cfg(feature = "alloc")]
141 InvalidSecurityLevel { level: u32, supported: Vec<u32> },
142 #[cfg(not(feature = "alloc"))]
143 InvalidSecurityLevel {
144 level: u32,
145 supported: &'static [u32],
146 },
147
148 #[cfg(feature = "alloc")]
154 VerificationFailed { operation: String },
155 #[cfg(not(feature = "alloc"))]
156 VerificationFailed { operation: &'static str },
157
158 #[cfg(feature = "alloc")]
164 EncryptionFailed { operation: String },
165 #[cfg(not(feature = "alloc"))]
166 EncryptionFailed { operation: &'static str },
167
168 #[cfg(feature = "alloc")]
174 DecryptionFailed { operation: String },
175 #[cfg(not(feature = "alloc"))]
176 DecryptionFailed { operation: &'static str },
177
178 #[cfg(feature = "alloc")]
184 KeyGenerationFailed { operation: String },
185 #[cfg(not(feature = "alloc"))]
186 KeyGenerationFailed { operation: &'static str },
187
188 #[cfg(feature = "alloc")]
194 RandomGenerationFailed { operation: String },
195 #[cfg(not(feature = "alloc"))]
196 RandomGenerationFailed { operation: &'static str },
197
198 #[cfg(feature = "alloc")]
204 SigningFailed { operation: String },
205 #[cfg(not(feature = "alloc"))]
206 SigningFailed { operation: &'static str },
207
208 #[cfg(feature = "alloc")]
214 MemoryAllocationFailed { operation: String },
215 #[cfg(not(feature = "alloc"))]
216 MemoryAllocationFailed { operation: &'static str },
217
218 #[cfg(feature = "alloc")]
224 InternalError { operation: String, details: String },
225 #[cfg(not(feature = "alloc"))]
226 InternalError {
227 operation: &'static str,
228 details: &'static str,
229 },
230
231 #[cfg(feature = "alloc")]
237 NotImplemented { feature: String },
238 #[cfg(not(feature = "alloc"))]
239 NotImplemented { feature: &'static str },
240
241 #[cfg(feature = "alloc")]
243 UnsupportedOperation { operation: String },
244 #[cfg(not(feature = "alloc"))]
245 UnsupportedOperation { operation: &'static str },
246
247 #[cfg(feature = "alloc")]
249 ProviderNotConfigured { operation: String },
250 #[cfg(not(feature = "alloc"))]
251 ProviderNotConfigured { operation: &'static str },
252
253 #[cfg(feature = "alloc")]
255 InvalidState { operation: String, reason: String },
256 #[cfg(not(feature = "alloc"))]
257 InvalidState {
258 operation: &'static str,
259 reason: &'static str,
260 },
261
262 #[cfg(feature = "alloc")]
264 PluginDependencyError {
265 plugin: String,
266 dependency: String,
267 required_version: String,
268 available_version: Option<String>,
269 },
270 #[cfg(not(feature = "alloc"))]
271 PluginDependencyError {
272 plugin: &'static str,
273 dependency: &'static str,
274 required_version: &'static str,
275 available_version: Option<&'static str>,
276 },
277
278 #[cfg(feature = "alloc")]
280 PluginVersionIncompatible {
281 plugin: String,
282 required_version: String,
283 available_version: String,
284 },
285 #[cfg(not(feature = "alloc"))]
286 PluginVersionIncompatible {
287 plugin: &'static str,
288 required_version: &'static str,
289 available_version: &'static str,
290 },
291
292 InvalidKeyFormat,
294
295 #[cfg(feature = "alloc")]
297 InvalidKey { key_type: String, reason: String },
298 #[cfg(not(feature = "alloc"))]
299 InvalidKey {
300 key_type: &'static str,
301 reason: &'static str,
302 },
303
304 #[cfg(feature = "alloc")]
306 UnsupportedAlgorithm { algorithm: String },
307 #[cfg(not(feature = "alloc"))]
308 UnsupportedAlgorithm { algorithm: &'static str },
309
310 #[cfg(feature = "alloc")]
312 AuthenticationFailed { operation: String },
313 #[cfg(not(feature = "alloc"))]
314 AuthenticationFailed { operation: &'static str },
315
316 InvalidRandomnessSize { expected: usize, actual: usize },
318
319 RandomBytesLengthInvalid {
324 min: usize,
325 max: usize,
326 requested: usize,
327 },
328
329 HexDecode(HexDecodeError),
331
332 BufferTooSmall { capacity: usize, requested: usize },
338}
339
340impl Error {
341 #[must_use]
347 pub const fn aead_ciphertext_shorter_than_tag(tag_len: usize, actual_len: usize) -> Self {
348 Self::InvalidCiphertextSize {
349 expected: tag_len,
350 actual: actual_len,
351 }
352 }
353}
354
355impl fmt::Display for Error {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 match self {
358 Error::InvalidKeySize { expected, actual } => {
359 write!(f, "Invalid key size: expected {expected}, got {actual}")
360 }
361 Error::InvalidSignatureSize { expected, actual } => {
362 write!(
363 f,
364 "Invalid signature size: expected {expected}, got {actual}"
365 )
366 }
367 Error::InvalidNonceSize { expected, actual } => {
368 write!(f, "Invalid nonce size: expected {expected}, got {actual}")
369 }
370 Error::InvalidMessageSize { max, actual } => {
371 write!(f, "Invalid message size: maximum {max}, got {actual}")
372 }
373 Error::InvalidCiphertextSize { expected, actual } => {
374 write!(
375 f,
376 "Invalid ciphertext size: expected {expected}, got {actual}"
377 )
378 }
379 Error::InvalidPlaintextSize { expected, actual } => {
380 write!(
381 f,
382 "Invalid plaintext size: expected {expected}, got {actual}"
383 )
384 }
385 Error::InvalidAssociatedDataSize { max, actual } => {
386 write!(
387 f,
388 "Invalid associated data size: maximum {max}, got {actual}"
389 )
390 }
391 Error::InvalidTagSize { expected, actual } => {
392 write!(f, "Invalid tag size: expected {expected}, got {actual}")
393 }
394 Error::InvalidHashSize { expected, actual } => {
395 write!(f, "Invalid hash size: expected {expected}, got {actual}")
396 }
397 Error::InvalidAlgorithm { algorithm } => {
398 write!(f, "Invalid algorithm: {algorithm}")
399 }
400 Error::InvalidSecurityLevel { level, supported } => {
401 write!(
402 f,
403 "Invalid security level: {level} (supported: {supported:?})"
404 )
405 }
406 Error::VerificationFailed { operation } => {
407 write!(f, "Verification failed: {operation}")
408 }
409 Error::EncryptionFailed { operation } => {
410 write!(f, "Encryption failed: {operation}")
411 }
412 Error::DecryptionFailed { operation } => {
413 write!(f, "Decryption failed: {operation}")
414 }
415 Error::KeyGenerationFailed { operation } => {
416 write!(f, "Key generation failed: {operation}")
417 }
418 Error::RandomGenerationFailed { operation } => {
419 write!(f, "Random generation failed: {operation}")
420 }
421 Error::SigningFailed { operation } => {
422 write!(f, "Signing failed: {operation}")
423 }
424 Error::MemoryAllocationFailed { operation } => {
425 write!(f, "Memory allocation failed: {operation}")
426 }
427 Error::InternalError { operation, details } => {
428 write!(f, "Internal error in {operation}: {details}")
429 }
430 Error::NotImplemented { feature } => {
431 write!(f, "Feature not implemented: {feature}")
432 }
433 Error::ProviderNotConfigured { operation } => {
434 write!(
435 f,
436 "Cryptographic provider not configured for {operation}; set a provider on the context"
437 )
438 }
439 Error::UnsupportedOperation { operation } => {
440 write!(f, "Unsupported operation: {operation}")
441 }
442 Error::InvalidState { operation, reason } => {
443 write!(f, "Invalid state in {operation}: {reason}")
444 }
445 #[cfg(feature = "alloc")]
446 Error::PluginDependencyError {
447 plugin,
448 dependency,
449 required_version,
450 available_version,
451 } => {
452 if let Some(available) = available_version {
453 write!(
454 f,
455 "Plugin '{plugin}' requires dependency '{dependency}' version {required_version}, but version {available} is available"
456 )
457 } else {
458 write!(
459 f,
460 "Plugin '{plugin}' requires dependency '{dependency}' version {required_version}, but it is not available"
461 )
462 }
463 }
464 #[cfg(not(feature = "alloc"))]
465 Error::PluginDependencyError {
466 plugin,
467 dependency,
468 required_version,
469 available_version,
470 } => {
471 if let Some(available) = available_version {
472 write!(
473 f,
474 "Plugin '{}' requires dependency '{}' version {}, but version {} is available",
475 plugin, dependency, required_version, available
476 )
477 } else {
478 write!(
479 f,
480 "Plugin '{}' requires dependency '{}' version {}, but it is not available",
481 plugin, dependency, required_version
482 )
483 }
484 }
485 #[cfg(feature = "alloc")]
486 Error::PluginVersionIncompatible {
487 plugin,
488 required_version,
489 available_version,
490 } => {
491 write!(
492 f,
493 "Plugin '{plugin}' version {available_version} is incompatible with required version {required_version}"
494 )
495 }
496 #[cfg(not(feature = "alloc"))]
497 Error::PluginVersionIncompatible {
498 plugin,
499 required_version,
500 available_version,
501 } => {
502 write!(
503 f,
504 "Plugin '{}' version {} is incompatible with required version {}",
505 plugin, available_version, required_version
506 )
507 }
508 Error::InvalidKeyFormat => {
509 write!(f, "Invalid key format")
510 }
511 Error::InvalidKey { key_type, reason } => {
512 write!(f, "Invalid {key_type}: {reason}")
513 }
514 Error::UnsupportedAlgorithm { algorithm } => {
515 write!(f, "Unsupported algorithm: {algorithm}")
516 }
517 Error::AuthenticationFailed { operation } => {
518 write!(f, "Authentication failed: {operation}")
519 }
520 Error::InvalidRandomnessSize { expected, actual } => {
521 write!(
522 f,
523 "Invalid randomness size: expected {expected}, got {actual}"
524 )
525 }
526 Error::RandomBytesLengthInvalid {
527 min,
528 max,
529 requested,
530 } => {
531 write!(
532 f,
533 "Invalid random_bytes length: requested {requested}, allowed inclusive range [{min}, {max}]"
534 )
535 }
536 Error::HexDecode(e) => {
537 write!(f, "Hex decode failed: {e}")
538 }
539 Error::BufferTooSmall {
540 capacity,
541 requested,
542 } => {
543 write!(
544 f,
545 "Insufficient fixed buffer capacity: capacity {capacity}, requested {requested}"
546 )
547 }
548 }
549 }
550}
551
552#[cfg(feature = "std")]
553impl std::error::Error for Error {}
554
555#[cfg(feature = "wasm")]
557impl From<Error> for wasm_bindgen::JsValue {
558 fn from(error: Error) -> Self {
559 use crate::wasm::error::error_to_js_value;
560 error_to_js_value(error)
561 }
562}
563
564pub type Result<T> = core::result::Result<T, Error>;
566
567#[cfg(feature = "wasm")]
569impl Error {
570 pub fn message(&self) -> String {
572 self.to_string()
573 }
574
575 pub fn error_type(&self) -> String {
577 match self {
578 Error::InvalidKeySize { .. } => "InvalidKeySize".to_string(),
579 Error::InvalidSignatureSize { .. } => "InvalidSignatureSize".to_string(),
580 Error::InvalidNonceSize { .. } => "InvalidNonceSize".to_string(),
581 Error::InvalidMessageSize { .. } => "InvalidMessageSize".to_string(),
582 Error::InvalidCiphertextSize { .. } => "InvalidCiphertextSize".to_string(),
583 Error::InvalidPlaintextSize { .. } => "InvalidPlaintextSize".to_string(),
584 Error::InvalidHashSize { .. } => "InvalidHashSize".to_string(),
585 Error::InvalidAlgorithm { .. } => "InvalidAlgorithm".to_string(),
586 Error::InvalidSecurityLevel { .. } => "InvalidSecurityLevel".to_string(),
587 Error::VerificationFailed { .. } => "VerificationFailed".to_string(),
588 Error::EncryptionFailed { .. } => "EncryptionFailed".to_string(),
589 Error::DecryptionFailed { .. } => "DecryptionFailed".to_string(),
590 Error::KeyGenerationFailed { .. } => "KeyGenerationFailed".to_string(),
591 Error::RandomGenerationFailed { .. } => "RandomGenerationFailed".to_string(),
592 Error::SigningFailed { .. } => "SigningFailed".to_string(),
593 Error::MemoryAllocationFailed { .. } => "MemoryAllocationFailed".to_string(),
594 Error::InternalError { .. } => "InternalError".to_string(),
595 Error::NotImplemented { .. } => "NotImplemented".to_string(),
596 Error::ProviderNotConfigured { .. } => "ProviderNotConfigured".to_string(),
597 Error::UnsupportedOperation { .. } => "UnsupportedOperation".to_string(),
598 Error::InvalidState { .. } => "InvalidState".to_string(),
599 Error::InvalidAssociatedDataSize { .. } => "InvalidAssociatedDataSize".to_string(),
600 Error::InvalidTagSize { .. } => "InvalidTagSize".to_string(),
601 Error::PluginDependencyError { .. } => "PluginDependencyError".to_string(),
602 Error::PluginVersionIncompatible { .. } => "PluginVersionIncompatible".to_string(),
603 Error::InvalidKeyFormat => "InvalidKeyFormat".to_string(),
604 Error::InvalidKey { .. } => "InvalidKey".to_string(),
605 Error::UnsupportedAlgorithm { .. } => "UnsupportedAlgorithm".to_string(),
606 Error::AuthenticationFailed { .. } => "AuthenticationFailed".to_string(),
607 Error::InvalidRandomnessSize { .. } => "InvalidRandomnessSize".to_string(),
608 Error::RandomBytesLengthInvalid { .. } => "RandomBytesLengthInvalid".to_string(),
609 Error::HexDecode(..) => "HexDecode".to_string(),
610 Error::BufferTooSmall { .. } => "BufferTooSmall".to_string(),
611 }
612 }
613}
614
615#[cfg(feature = "wasm")]
616impl From<wasm_bindgen::JsValue> for Error {
617 fn from(_js_value: wasm_bindgen::JsValue) -> Self {
618 Error::InternalError {
621 operation: "WASM operation".to_string(),
622 details: "WASM error conversion".to_string(),
623 }
624 }
625}
626
627pub const SECURITY_LEVELS: &[u32] = &[1, 3, 4, 5];
629
630#[cfg(feature = "alloc")]
632pub fn supported_security_levels() -> Vec<u32> {
633 SECURITY_LEVELS.to_vec()
634}
635
636#[cfg(not(feature = "alloc"))]
637pub fn supported_security_levels() -> &'static [u32] {
638 SECURITY_LEVELS
639}
640
641pub fn is_supported_security_level(level: u32) -> bool {
643 SECURITY_LEVELS.contains(&level)
644}
645
646#[cfg(test)]
647mod tests {
648 use super::*;
649
650 #[test]
651 fn test_error_display() {
652 #[cfg(not(feature = "std"))]
653 use alloc::string::ToString;
654
655 let error = Error::InvalidKeySize {
656 expected: 32,
657 actual: 16,
658 };
659 assert_eq!(error.to_string(), "Invalid key size: expected 32, got 16");
660 }
661
662 #[test]
663 fn test_invalid_key_error_display() {
664 #[cfg(feature = "alloc")]
665 {
666 let error = Error::InvalidKey {
667 key_type: "public key".to_string(),
668 reason: "cannot be used for encapsulation".to_string(),
669 };
670 assert_eq!(
671 error.to_string(),
672 "Invalid public key: cannot be used for encapsulation"
673 );
674 }
675 #[cfg(not(feature = "alloc"))]
676 {
677 #[cfg(not(feature = "std"))]
678 use alloc::string::ToString;
679
680 let error = Error::InvalidKey {
681 key_type: "public key",
682 reason: "cannot be used for encapsulation",
683 };
684 assert_eq!(
685 error.to_string(),
686 "Invalid public key: cannot be used for encapsulation"
687 );
688 }
689 }
690
691 #[test]
692 fn test_security_levels() {
693 assert!(is_supported_security_level(1));
694 assert!(is_supported_security_level(3));
695 assert!(is_supported_security_level(4));
696 assert!(is_supported_security_level(5));
697 assert!(!is_supported_security_level(2));
698 assert!(!is_supported_security_level(6));
699 }
700}