1use crate::errors::{BottleError, Result};
38use const_oid::{db::rfc5912, ObjectIdentifier};
39use der::{Decode, Encode};
40use pkcs8::{AlgorithmIdentifierRef, PrivateKeyInfo};
41use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum KeyType {
46 EcdsaP256,
48 EcdsaP384,
50 EcdsaP521,
52 Ed25519,
54 X25519,
56 Rsa,
58 #[cfg(feature = "ml-kem")]
60 MlKem768,
61 #[cfg(feature = "ml-kem")]
63 MlKem1024,
64 #[cfg(feature = "post-quantum")]
66 MlDsa44,
67 #[cfg(feature = "post-quantum")]
69 MlDsa65,
70 #[cfg(feature = "post-quantum")]
72 MlDsa87,
73 #[cfg(feature = "post-quantum")]
75 SlhDsa128s,
76 #[cfg(feature = "post-quantum")]
78 SlhDsa128f,
79 #[cfg(feature = "post-quantum")]
81 SlhDsa192s,
82 #[cfg(feature = "post-quantum")]
84 SlhDsa192f,
85 #[cfg(feature = "post-quantum")]
87 SlhDsa256s,
88 #[cfg(feature = "post-quantum")]
90 SlhDsa256f,
91 #[cfg(feature = "post-quantum")]
93 SlhDsaSha2_128s,
94 #[cfg(feature = "post-quantum")]
96 SlhDsaSha2_128f,
97 #[cfg(feature = "post-quantum")]
99 SlhDsaSha2_192s,
100 #[cfg(feature = "post-quantum")]
102 SlhDsaSha2_192f,
103 #[cfg(feature = "post-quantum")]
105 SlhDsaSha2_256s,
106 #[cfg(feature = "post-quantum")]
108 SlhDsaSha2_256f,
109}
110
111impl KeyType {
112 fn oid(&self) -> ObjectIdentifier {
114 match self {
115 KeyType::EcdsaP256 => rfc5912::ID_EC_PUBLIC_KEY, KeyType::EcdsaP384 => rfc5912::ID_EC_PUBLIC_KEY, KeyType::EcdsaP521 => rfc5912::ID_EC_PUBLIC_KEY, KeyType::Ed25519 => ObjectIdentifier::new("1.3.101.112").expect("Invalid Ed25519 OID"), KeyType::X25519 => ObjectIdentifier::new("1.3.101.110").expect("Invalid X25519 OID"), KeyType::Rsa => rfc5912::RSA_ENCRYPTION, #[cfg(feature = "ml-kem")]
122 KeyType::MlKem768 | KeyType::MlKem1024 => {
123 ObjectIdentifier::new("1.3.6.1.4.1.2.267.7.6.5").expect("Invalid ML-KEM OID")
127 }
128 #[cfg(feature = "post-quantum")]
129 KeyType::MlDsa44 | KeyType::MlDsa65 | KeyType::MlDsa87 => {
130 ObjectIdentifier::new("1.3.6.1.4.1.2.267.7.4.4").expect("Invalid ML-DSA OID")
133 }
134 #[cfg(feature = "post-quantum")]
135 KeyType::SlhDsa128s | KeyType::SlhDsa128f | KeyType::SlhDsa192s | KeyType::SlhDsa192f | KeyType::SlhDsa256s | KeyType::SlhDsa256f
136 | KeyType::SlhDsaSha2_128s | KeyType::SlhDsaSha2_128f | KeyType::SlhDsaSha2_192s | KeyType::SlhDsaSha2_192f | KeyType::SlhDsaSha2_256s | KeyType::SlhDsaSha2_256f => {
137 ObjectIdentifier::new("1.3.6.1.4.1.2.267.1.16.7").expect("Invalid SLH-DSA OID")
140 }
141 }
142 }
143
144 #[allow(dead_code)]
146 fn curve_oid(&self) -> Option<&'static [u32]> {
147 match self {
148 KeyType::EcdsaP256 => Some(&[1, 2, 840, 10045, 3, 1, 7]), KeyType::EcdsaP384 => Some(&[1, 3, 132, 0, 34]), KeyType::EcdsaP521 => Some(&[1, 3, 132, 0, 35]), _ => None,
152 }
153 }
154}
155
156pub fn marshal_pkix_public_key(public_key_bytes: &[u8]) -> Result<Vec<u8>> {
183 let key_type = detect_key_type_from_public_key(public_key_bytes)?;
185 marshal_pkix_public_key_with_type(public_key_bytes, key_type)
186}
187
188pub fn marshal_pkix_public_key_with_type(
200 public_key_bytes: &[u8],
201 key_type: KeyType,
202) -> Result<Vec<u8>> {
203 match key_type {
204 KeyType::EcdsaP256 | KeyType::EcdsaP384 | KeyType::EcdsaP521 => {
205 marshal_ecdsa_pkix(public_key_bytes, key_type)
206 }
207 KeyType::Ed25519 => marshal_ed25519_pkix(public_key_bytes),
208 KeyType::X25519 => marshal_x25519_pkix(public_key_bytes),
209 KeyType::Rsa => marshal_rsa_pkix(public_key_bytes),
210 #[cfg(feature = "ml-kem")]
211 KeyType::MlKem768 | KeyType::MlKem1024 => marshal_mlkem_pkix(public_key_bytes, key_type),
212 #[cfg(feature = "post-quantum")]
213 KeyType::MlDsa44 | KeyType::MlDsa65 | KeyType::MlDsa87 => {
214 marshal_mldsa_pkix(public_key_bytes, key_type)
215 }
216 #[cfg(feature = "post-quantum")]
217 KeyType::SlhDsa128s | KeyType::SlhDsa128f | KeyType::SlhDsa192s | KeyType::SlhDsa192f | KeyType::SlhDsa256s | KeyType::SlhDsa256f
218 | KeyType::SlhDsaSha2_128s | KeyType::SlhDsaSha2_128f | KeyType::SlhDsaSha2_192s | KeyType::SlhDsaSha2_192f | KeyType::SlhDsaSha2_256s | KeyType::SlhDsaSha2_256f => {
219 marshal_slhdsa_pkix(public_key_bytes, key_type)
220 }
221 }
222}
223
224pub fn marshal_pkix_public_key_pem(public_key_bytes: &[u8]) -> Result<String> {
247 let der = marshal_pkix_public_key(public_key_bytes)?;
248 let pem = pem::encode(&pem::Pem::new("PUBLIC KEY", der));
249 Ok(pem)
250}
251
252pub fn parse_pkix_public_key(der_bytes: &[u8]) -> Result<Vec<u8>> {
278 use der::asn1::AnyRef;
279 use der::asn1::BitString;
280 let spki: SubjectPublicKeyInfo<AnyRef, BitString> = SubjectPublicKeyInfo::from_der(der_bytes)
281 .map_err(|e| {
282 BottleError::Deserialization(format!("Failed to parse PKIX public key: {}", e))
283 })?;
284
285 Ok(spki.subject_public_key.raw_bytes().to_vec())
290}
291
292pub fn parse_pkix_public_key_pem(pem_str: &str) -> Result<Vec<u8>> {
303 let pem = pem::parse(pem_str)
304 .map_err(|e| BottleError::Deserialization(format!("Failed to parse PEM: {}", e)))?;
305 parse_pkix_public_key(pem.contents())
306}
307
308pub fn marshal_pkcs8_private_key(private_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
335 match key_type {
336 KeyType::EcdsaP256 | KeyType::EcdsaP384 | KeyType::EcdsaP521 => {
337 marshal_ecdsa_pkcs8(private_key_bytes, key_type)
338 }
339 KeyType::Ed25519 => marshal_ed25519_pkcs8(private_key_bytes),
340 KeyType::X25519 => marshal_x25519_pkcs8(private_key_bytes),
341 KeyType::Rsa => marshal_rsa_pkcs8(private_key_bytes),
342 #[cfg(feature = "ml-kem")]
343 KeyType::MlKem768 | KeyType::MlKem1024 => marshal_mlkem_pkcs8(private_key_bytes, key_type),
344 #[cfg(feature = "post-quantum")]
345 KeyType::MlDsa44 | KeyType::MlDsa65 | KeyType::MlDsa87 => {
346 marshal_mldsa_pkcs8(private_key_bytes, key_type)
347 }
348 #[cfg(feature = "post-quantum")]
349 KeyType::SlhDsa128s | KeyType::SlhDsa128f | KeyType::SlhDsa192s | KeyType::SlhDsa192f | KeyType::SlhDsa256s | KeyType::SlhDsa256f
350 | KeyType::SlhDsaSha2_128s | KeyType::SlhDsaSha2_128f | KeyType::SlhDsaSha2_192s | KeyType::SlhDsaSha2_192f | KeyType::SlhDsaSha2_256s | KeyType::SlhDsaSha2_256f => {
351 marshal_slhdsa_pkcs8(private_key_bytes, key_type)
352 }
353 }
354}
355
356pub fn marshal_pkcs8_private_key_pem(
383 private_key_bytes: &[u8],
384 key_type: KeyType,
385) -> Result<String> {
386 let der = marshal_pkcs8_private_key(private_key_bytes, key_type)?;
387 let pem = pem::encode(&pem::Pem::new("PRIVATE KEY", der));
388 Ok(pem)
389}
390
391pub fn parse_pkcs8_private_key(der_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
420 match key_type {
421 KeyType::EcdsaP256 => {
422 use p256::ecdsa::SigningKey;
423 use p256::pkcs8::DecodePrivateKey;
424 let signing_key = SigningKey::from_pkcs8_der(der_bytes).map_err(|e| {
425 BottleError::Deserialization(format!("Failed to parse P-256 PKCS#8: {}", e))
426 })?;
427 Ok(signing_key.to_bytes().to_vec())
428 }
429 KeyType::Ed25519 => {
430 use ed25519_dalek::pkcs8::DecodePrivateKey;
431 use ed25519_dalek::SigningKey;
432 let signing_key = SigningKey::from_pkcs8_der(der_bytes).map_err(|e| {
433 BottleError::Deserialization(format!("Failed to parse Ed25519 PKCS#8: {}", e))
434 })?;
435 Ok(signing_key.to_bytes().to_vec())
436 }
437 KeyType::X25519 => {
438 let pkcs8 = PrivateKeyInfo::from_der(der_bytes).map_err(|e| {
440 BottleError::Deserialization(format!("Failed to parse PKCS#8 private key: {}", e))
441 })?;
442 Ok(pkcs8.private_key.to_vec())
443 }
444 KeyType::Rsa => {
445 Err(BottleError::Deserialization(
449 "RSA PKCS#8 deserialization not yet implemented. Use RsaKey directly.".to_string(),
450 ))
451 }
452 _ => {
453 let pkcs8 = PrivateKeyInfo::from_der(der_bytes).map_err(|e| {
456 BottleError::Deserialization(format!("Failed to parse PKCS#8 private key: {}", e))
457 })?;
458 Ok(pkcs8.private_key.to_vec())
459 }
460 }
461}
462
463pub fn parse_pkcs8_private_key_pem(pem_str: &str, key_type: KeyType) -> Result<Vec<u8>> {
475 let pem = pem::parse(pem_str)
476 .map_err(|e| BottleError::Deserialization(format!("Failed to parse PEM: {}", e)))?;
477 parse_pkcs8_private_key(pem.contents(), key_type)
478}
479
480fn marshal_ecdsa_pkix(public_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
483 match key_type {
484 KeyType::EcdsaP256 => {
485 use p256::pkcs8::EncodePublicKey;
486 let pub_key = p256::PublicKey::from_sec1_bytes(public_key_bytes).map_err(|e| {
487 BottleError::Serialization(format!("Failed to create P-256 public key: {}", e))
488 })?;
489 pub_key
490 .to_public_key_der()
491 .map(|doc| doc.as_bytes().to_vec())
492 .map_err(|e| {
493 BottleError::Serialization(format!("Failed to encode P-256 PKIX: {}", e))
494 })
495 }
496 _ => Err(BottleError::UnsupportedAlgorithm),
497 }
498}
499
500fn marshal_ecdsa_pkcs8(private_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
501 match key_type {
502 KeyType::EcdsaP256 => {
503 use p256::ecdsa::SigningKey;
504 use p256::pkcs8::EncodePrivateKey;
505 let signing_key = SigningKey::from_bytes(private_key_bytes.into()).map_err(|e| {
506 BottleError::Serialization(format!("Invalid P-256 private key: {}", e))
507 })?;
508 signing_key
509 .to_pkcs8_der()
510 .map(|doc| doc.as_bytes().to_vec())
511 .map_err(|e| {
512 BottleError::Serialization(format!("Failed to encode P-256 PKCS#8: {}", e))
513 })
514 }
515 _ => Err(BottleError::UnsupportedAlgorithm),
516 }
517}
518
519fn marshal_ed25519_pkix(public_key_bytes: &[u8]) -> Result<Vec<u8>> {
520 use ed25519_dalek::pkcs8::EncodePublicKey;
521 use ed25519_dalek::VerifyingKey;
522
523 let verifying_key = VerifyingKey::from_bytes(public_key_bytes.try_into().map_err(|_| {
524 BottleError::Serialization("Invalid Ed25519 public key length".to_string())
525 })?)
526 .map_err(|e| BottleError::Serialization(format!("Invalid Ed25519 public key: {}", e)))?;
527
528 verifying_key
529 .to_public_key_der()
530 .map(|doc| doc.as_bytes().to_vec())
531 .map_err(|e| BottleError::Serialization(format!("Failed to encode Ed25519 PKIX: {}", e)))
532}
533
534fn marshal_ed25519_pkcs8(private_key_bytes: &[u8]) -> Result<Vec<u8>> {
535 use ed25519_dalek::pkcs8::EncodePrivateKey;
536 use ed25519_dalek::SigningKey;
537
538 let signing_key = SigningKey::from_bytes(private_key_bytes.try_into().map_err(|_| {
539 BottleError::Serialization("Invalid Ed25519 private key length".to_string())
540 })?);
541
542 signing_key
543 .to_pkcs8_der()
544 .map(|doc| doc.as_bytes().to_vec())
545 .map_err(|e| BottleError::Serialization(format!("Failed to encode Ed25519 PKCS#8: {}", e)))
546}
547
548fn marshal_x25519_pkix(public_key_bytes: &[u8]) -> Result<Vec<u8>> {
549 if public_key_bytes.len() != 32 {
551 return Err(BottleError::Serialization(
552 "Invalid X25519 public key length".to_string(),
553 ));
554 }
555
556 use der::asn1::OctetString;
559 let key_octets = OctetString::new(public_key_bytes).map_err(|e| {
560 BottleError::Serialization(format!("Failed to create X25519 octet string: {}", e))
561 })?;
562
563 use der::asn1::AnyRef;
566 let algorithm = AlgorithmIdentifier {
567 oid: KeyType::X25519.oid(),
568 parameters: None::<AnyRef>,
569 };
570
571 let spki = SubjectPublicKeyInfo {
572 algorithm,
573 subject_public_key: key_octets,
574 };
575
576 spki.to_der()
577 .map_err(|e| BottleError::Serialization(format!("Failed to encode X25519 PKIX: {}", e)))
578}
579
580fn marshal_x25519_pkcs8(private_key_bytes: &[u8]) -> Result<Vec<u8>> {
581 if private_key_bytes.len() != 32 {
583 return Err(BottleError::Serialization(
584 "Invalid X25519 private key length".to_string(),
585 ));
586 }
587
588 let algorithm = AlgorithmIdentifierRef {
591 oid: KeyType::X25519.oid(),
592 parameters: None,
593 };
594
595 let pkcs8 = PrivateKeyInfo::new(algorithm, private_key_bytes);
596
597 pkcs8
598 .to_der()
599 .map_err(|e| BottleError::Serialization(format!("Failed to encode X25519 PKCS#8: {}", e)))
600}
601
602fn marshal_rsa_pkix(_public_key_bytes: &[u8]) -> Result<Vec<u8>> {
603 Err(BottleError::Serialization(
608 "RSA PKIX serialization requires RsaPublicKey reference. Use PKCS#8 serialization or provide RsaPublicKey directly.".to_string()
609 ))
610}
611
612fn marshal_rsa_pkcs8(_private_key_bytes: &[u8]) -> Result<Vec<u8>> {
613 Err(BottleError::Serialization(
618 "RSA PKCS#8 serialization requires RsaPrivateKey reference. Use RsaKey directly or provide RsaPrivateKey.".to_string()
619 ))
620}
621
622#[cfg(feature = "ml-kem")]
623fn marshal_mlkem_pkix(public_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
624 use der::asn1::BitString;
625
626 let key_bits = BitString::from_bytes(public_key_bytes).map_err(|e| {
627 BottleError::Serialization(format!("Failed to create ML-KEM bit string: {}", e))
628 })?;
629
630 use der::asn1::AnyRef;
631 let algorithm = AlgorithmIdentifier {
632 oid: key_type.oid(),
633 parameters: Some(AnyRef::NULL),
634 };
635
636 let spki = SubjectPublicKeyInfo {
637 algorithm,
638 subject_public_key: key_bits,
639 };
640
641 spki.to_der()
642 .map_err(|e| BottleError::Serialization(format!("Failed to encode ML-KEM PKIX: {}", e)))
643}
644
645#[cfg(feature = "ml-kem")]
646fn marshal_mlkem_pkcs8(private_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
647 use der::asn1::OctetString;
648
649 let _key_octets = OctetString::new(private_key_bytes).map_err(|e| {
650 BottleError::Serialization(format!("Failed to create ML-KEM octet string: {}", e))
651 })?;
652
653 use der::asn1::AnyRef;
654 let algorithm = AlgorithmIdentifierRef {
655 oid: key_type.oid(),
656 parameters: Some(AnyRef::NULL),
657 };
658
659 let pkcs8 = PrivateKeyInfo::new(algorithm, private_key_bytes);
660
661 pkcs8
662 .to_der()
663 .map_err(|e| BottleError::Serialization(format!("Failed to encode ML-KEM PKCS#8: {}", e)))
664}
665
666#[cfg(feature = "post-quantum")]
667fn marshal_mldsa_pkix(public_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
668 use der::asn1::BitString;
669
670 let key_bits = BitString::from_bytes(public_key_bytes).map_err(|e| {
671 BottleError::Serialization(format!("Failed to create ML-DSA bit string: {}", e))
672 })?;
673
674 use der::asn1::AnyRef;
675 let algorithm = AlgorithmIdentifier {
676 oid: key_type.oid(),
677 parameters: Some(AnyRef::NULL),
678 };
679
680 let spki = SubjectPublicKeyInfo {
681 algorithm,
682 subject_public_key: key_bits,
683 };
684
685 spki.to_der()
686 .map_err(|e| BottleError::Serialization(format!("Failed to encode ML-DSA PKIX: {}", e)))
687}
688
689#[cfg(feature = "post-quantum")]
690fn marshal_mldsa_pkcs8(private_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
691 use der::asn1::OctetString;
692
693 let _key_octets = OctetString::new(private_key_bytes).map_err(|e| {
694 BottleError::Serialization(format!("Failed to create ML-DSA octet string: {}", e))
695 })?;
696
697 use der::asn1::AnyRef;
698 let algorithm = AlgorithmIdentifierRef {
699 oid: key_type.oid(),
700 parameters: Some(AnyRef::NULL),
701 };
702
703 let pkcs8 = PrivateKeyInfo::new(algorithm, private_key_bytes);
704
705 pkcs8
706 .to_der()
707 .map_err(|e| BottleError::Serialization(format!("Failed to encode ML-DSA PKCS#8: {}", e)))
708}
709
710#[cfg(feature = "post-quantum")]
711fn marshal_slhdsa_pkix(public_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
712 use der::asn1::BitString;
713
714 let key_bits = BitString::from_bytes(public_key_bytes).map_err(|e| {
715 BottleError::Serialization(format!("Failed to create SLH-DSA bit string: {}", e))
716 })?;
717
718 use der::asn1::AnyRef;
719 let algorithm = AlgorithmIdentifier {
720 oid: key_type.oid(),
721 parameters: Some(AnyRef::NULL),
722 };
723
724 let spki = SubjectPublicKeyInfo {
725 algorithm,
726 subject_public_key: key_bits,
727 };
728
729 spki.to_der()
730 .map_err(|e| BottleError::Serialization(format!("Failed to encode SLH-DSA PKIX: {}", e)))
731}
732
733#[cfg(feature = "post-quantum")]
734fn marshal_slhdsa_pkcs8(private_key_bytes: &[u8], key_type: KeyType) -> Result<Vec<u8>> {
735 use der::asn1::OctetString;
736
737 let _key_octets = OctetString::new(private_key_bytes).map_err(|e| {
738 BottleError::Serialization(format!("Failed to create SLH-DSA octet string: {}", e))
739 })?;
740
741 use der::asn1::AnyRef;
742 let algorithm = AlgorithmIdentifierRef {
743 oid: key_type.oid(),
744 parameters: Some(AnyRef::NULL),
745 };
746
747 let pkcs8 = PrivateKeyInfo::new(algorithm, private_key_bytes);
748
749 pkcs8
750 .to_der()
751 .map_err(|e| BottleError::Serialization(format!("Failed to encode SLH-DSA PKCS#8: {}", e)))
752}
753
754fn detect_key_type_from_public_key(public_key_bytes: &[u8]) -> Result<KeyType> {
756 match public_key_bytes.len() {
757 32 => {
758 #[cfg(feature = "post-quantum")]
761 {
762 Ok(KeyType::Ed25519)
764 }
765 #[cfg(not(feature = "post-quantum"))]
766 {
767 Ok(KeyType::Ed25519)
768 }
769 }
770 65 => {
771 if public_key_bytes[0] == 0x04 {
773 Ok(KeyType::EcdsaP256)
774 } else {
775 Err(BottleError::InvalidKeyType)
776 }
777 }
778 97 => {
779 if public_key_bytes[0] == 0x04 {
781 Ok(KeyType::EcdsaP384)
782 } else {
783 Err(BottleError::InvalidKeyType)
784 }
785 }
786 133 => {
787 if public_key_bytes[0] == 0x04 {
789 Ok(KeyType::EcdsaP521)
790 } else {
791 Err(BottleError::InvalidKeyType)
792 }
793 }
794 1184 => {
795 #[cfg(feature = "ml-kem")]
796 {
797 Ok(KeyType::MlKem768)
798 }
799 #[cfg(not(feature = "ml-kem"))]
800 {
801 Err(BottleError::InvalidKeyType)
802 }
803 }
804 1568 => {
805 #[cfg(feature = "ml-kem")]
806 {
807 Ok(KeyType::MlKem1024)
808 }
809 #[cfg(not(feature = "ml-kem"))]
810 {
811 Err(BottleError::InvalidKeyType)
812 }
813 }
814 1312 => {
815 #[cfg(feature = "post-quantum")]
816 {
817 Ok(KeyType::MlDsa44)
818 }
819 #[cfg(not(feature = "post-quantum"))]
820 {
821 Err(BottleError::InvalidKeyType)
822 }
823 }
824 1952 => {
825 #[cfg(feature = "post-quantum")]
826 {
827 Ok(KeyType::MlDsa65)
828 }
829 #[cfg(not(feature = "post-quantum"))]
830 {
831 Err(BottleError::InvalidKeyType)
832 }
833 }
834 2592 => {
835 #[cfg(feature = "post-quantum")]
836 {
837 Ok(KeyType::MlDsa87)
838 }
839 #[cfg(not(feature = "post-quantum"))]
840 {
841 Err(BottleError::InvalidKeyType)
842 }
843 }
844 48 => {
845 #[cfg(feature = "post-quantum")]
846 {
847 Ok(KeyType::SlhDsa192s)
848 }
849 #[cfg(not(feature = "post-quantum"))]
850 {
851 Err(BottleError::InvalidKeyType)
852 }
853 }
854 64 => {
855 #[cfg(feature = "post-quantum")]
856 {
857 Ok(KeyType::SlhDsa256s)
858 }
859 #[cfg(not(feature = "post-quantum"))]
860 {
861 Err(BottleError::InvalidKeyType)
862 }
863 }
864 _ => Err(BottleError::InvalidKeyType),
865 }
866}