@@ -16,6 +16,7 @@ use tss_esapi::attributes::NvIndexAttributesBuilder;
1616use tss_esapi:: handles:: AuthHandle ;
1717use tss_esapi:: interface_types:: algorithm:: { HashingAlgorithm , SymmetricMode } ;
1818use tss_esapi:: interface_types:: ecc:: EccCurve ;
19+ use tss_esapi:: interface_types:: key_bits:: { AesKeyBits , CamelliaKeyBits , Sm4KeyBits } ;
1920use tss_esapi:: interface_types:: reserved_handles:: { Hierarchy , HierarchyAuth , Provision } ;
2021use tss_esapi:: structures:: {
2122 Auth , Data , HashScheme , PcrSelectionList , PcrSelectionListBuilder , PcrSlot , SensitiveData ,
@@ -484,21 +485,130 @@ pub fn parse_ecc_curve(s: &str) -> Result<EccCurve, String> {
484485// Symmetric definition (for sessions)
485486// ---------------------------------------------------------------------------
486487
487- /// Parse a symmetric algorithm definition for session encryption .
488+ /// Parse a symmetric algorithm definition.
488489///
489- /// Accepted values: `aes128cfb`, `aes256cfb`, `xor`, `null`.
490+ /// Accepted formats:
491+ /// - `aes-{128,192,256}-{cfb,cbc,ecb,ofb,ctr}` — AES with key size and mode
492+ /// - `sm4-128-{cfb,cbc,ecb,ofb,ctr}` — SM4 with key size and mode
493+ /// - `camellia-{128,192,256}-{cfb,cbc,ecb,ofb,ctr}` — Camellia with key size and mode
494+ /// - `xor-{sha1,sha256,...}` — XOR with a hashing algorithm
495+ /// - `null` — no symmetric algorithm
496+ ///
497+ /// Legacy shorthand forms `aes128cfb` and `aes256cfb` are also accepted.
490498///
491499/// Intended for use as a clap `value_parser`.
492500pub fn parse_symmetric_definition ( s : & str ) -> Result < SymmetricDefinition , String > {
493- match s. to_lowercase ( ) . as_str ( ) {
494- "aes128cfb" | "aes-128-cfb" => Ok ( SymmetricDefinition :: AES_128_CFB ) ,
495- "aes256cfb" | "aes-256-cfb" => Ok ( SymmetricDefinition :: AES_256_CFB ) ,
496- "xor" => Ok ( SymmetricDefinition :: Xor {
497- hashing_algorithm : HashingAlgorithm :: Sha256 ,
498- } ) ,
499- "null" => Ok ( SymmetricDefinition :: Null ) ,
501+ let lower = s. to_lowercase ( ) ;
502+
503+ // Handle "null" first.
504+ if lower == "null" {
505+ return Ok ( SymmetricDefinition :: Null ) ;
506+ }
507+
508+ // Legacy shorthand aliases for backwards compatibility.
509+ match lower. as_str ( ) {
510+ "aes128cfb" => {
511+ return Ok ( SymmetricDefinition :: Aes {
512+ key_bits : AesKeyBits :: Aes128 ,
513+ mode : SymmetricMode :: Cfb ,
514+ } ) ;
515+ }
516+ "aes256cfb" => {
517+ return Ok ( SymmetricDefinition :: Aes {
518+ key_bits : AesKeyBits :: Aes256 ,
519+ mode : SymmetricMode :: Cfb ,
520+ } ) ;
521+ }
522+ "xor" => {
523+ return Ok ( SymmetricDefinition :: Xor {
524+ hashing_algorithm : HashingAlgorithm :: Sha256 ,
525+ } ) ;
526+ }
527+ _ => { }
528+ }
529+
530+ let parts: Vec < & str > = lower. split ( '-' ) . collect ( ) ;
531+
532+ match parts[ 0 ] {
533+ "aes" => {
534+ if parts. len ( ) != 3 {
535+ return Err ( format ! (
536+ "expected 'aes-<bits>-<mode>' (e.g. aes-128-cfb), got: '{s}'"
537+ ) ) ;
538+ }
539+ let key_bits = match parts[ 1 ] {
540+ "128" => AesKeyBits :: Aes128 ,
541+ "192" => AesKeyBits :: Aes192 ,
542+ "256" => AesKeyBits :: Aes256 ,
543+ _ => {
544+ return Err ( format ! (
545+ "unsupported AES key size: {} (expected 128, 192, or 256)" ,
546+ parts[ 1 ]
547+ ) ) ;
548+ }
549+ } ;
550+ let mode = parse_symmetric_mode ( parts[ 2 ] ) ?;
551+ if mode == SymmetricMode :: Null {
552+ return Err ( format ! ( "unsupported AES symmetric mode: {}" , parts[ 2 ] ) ) ;
553+ } ;
554+ Ok ( SymmetricDefinition :: Aes { key_bits, mode } )
555+ }
556+ "sm4" => {
557+ if parts. len ( ) != 3 {
558+ return Err ( format ! (
559+ "expected 'sm4-128-<mode>' (e.g. sm4-128-cfb), got: '{s}'"
560+ ) ) ;
561+ }
562+ let key_bits = match parts[ 1 ] {
563+ "128" => Sm4KeyBits :: Sm4_128 ,
564+ _ => {
565+ return Err ( format ! (
566+ "unsupported SM4 key size: {} (expected 128)" ,
567+ parts[ 1 ]
568+ ) ) ;
569+ }
570+ } ;
571+ let mode = parse_symmetric_mode ( parts[ 2 ] ) ?;
572+ if mode == SymmetricMode :: Null {
573+ return Err ( format ! ( "unsupported SM4 symmetric mode: {}" , parts[ 2 ] ) ) ;
574+ } ;
575+ Ok ( SymmetricDefinition :: Sm4 { key_bits, mode } )
576+ }
577+ "camellia" => {
578+ if parts. len ( ) != 3 {
579+ return Err ( format ! (
580+ "expected 'camellia-<bits>-<mode>' (e.g. camellia-128-cfb), got: '{s}'"
581+ ) ) ;
582+ }
583+ let key_bits = match parts[ 1 ] {
584+ "128" => CamelliaKeyBits :: Camellia128 ,
585+ "192" => CamelliaKeyBits :: Camellia192 ,
586+ "256" => CamelliaKeyBits :: Camellia256 ,
587+ _ => {
588+ return Err ( format ! (
589+ "unsupported Camellia key size: {} (expected 128, 192, or 256)" ,
590+ parts[ 1 ]
591+ ) ) ;
592+ }
593+ } ;
594+ let mode = parse_symmetric_mode ( parts[ 2 ] ) ?;
595+ if mode == SymmetricMode :: Null {
596+ return Err ( format ! ( "unsupported Camellia symmetric mode: {}" , parts[ 2 ] ) ) ;
597+ } ;
598+ Ok ( SymmetricDefinition :: Camellia { key_bits, mode } )
599+ }
600+ "xor" => {
601+ if parts. len ( ) != 2 {
602+ return Err ( format ! (
603+ "expected 'xor-<hash>' (e.g. xor-sha256), got: '{s}'"
604+ ) ) ;
605+ }
606+ let hashing_algorithm = parse_hashing_algorithm ( parts[ 1 ] ) ?;
607+ Ok ( SymmetricDefinition :: Xor { hashing_algorithm } )
608+ }
500609 _ => Err ( format ! (
501- "unsupported symmetric definition: {s} (supported: aes128cfb, aes256cfb, xor, null)"
610+ "unsupported symmetric algorithm: '{}'; expected aes, sm4, camellia, xor, or null" ,
611+ parts[ 0 ]
502612 ) ) ,
503613 }
504614}
@@ -569,3 +679,87 @@ pub fn parse_tpm2_operation(s: &str) -> Result<u16, String> {
569679 ) ) ,
570680 }
571681}
682+
683+ // ===========================================================================
684+ // Tests
685+ // ===========================================================================
686+
687+ #[ test]
688+ fn symdef_aes_256_cbc ( ) {
689+ let def = parse_symmetric_definition ( "aes-256-cbc" ) . unwrap ( ) ;
690+ assert ! ( matches!(
691+ def,
692+ SymmetricDefinition :: Aes {
693+ key_bits: AesKeyBits :: Aes256 ,
694+ mode: SymmetricMode :: Cbc ,
695+ }
696+ ) ) ;
697+ }
698+
699+ #[ test]
700+ fn symdef_camellia_192_ecb ( ) {
701+ let def = parse_symmetric_definition ( "camellia-192-ecb" ) . unwrap ( ) ;
702+ assert ! ( matches!(
703+ def,
704+ SymmetricDefinition :: Camellia {
705+ key_bits: CamelliaKeyBits :: Camellia192 ,
706+ mode: SymmetricMode :: Ecb ,
707+ }
708+ ) ) ;
709+ }
710+
711+ #[ test]
712+ fn symdef_xor_sha1 ( ) {
713+ let def = parse_symmetric_definition ( "xor-sha1" ) . unwrap ( ) ;
714+ assert ! ( matches!(
715+ def,
716+ SymmetricDefinition :: Xor {
717+ hashing_algorithm: HashingAlgorithm :: Sha1 ,
718+ }
719+ ) ) ;
720+ }
721+
722+ // Legacy shorthand forms
723+ #[ test]
724+ fn symdef_aes128cfb ( ) {
725+ let def = parse_symmetric_definition ( "aes128cfb" ) . unwrap ( ) ;
726+ assert ! ( matches!( def, SymmetricDefinition :: AES_128_CFB ) ) ;
727+ }
728+
729+ #[ test]
730+ fn symdef_aes256cfb ( ) {
731+ let def = parse_symmetric_definition ( "aes256cfb" ) . unwrap ( ) ;
732+ assert ! ( matches!( def, SymmetricDefinition :: AES_256_CFB ) ) ;
733+ }
734+
735+ #[ test]
736+ fn symdef_xor ( ) {
737+ let def = parse_symmetric_definition ( "xor" ) . unwrap ( ) ;
738+ assert ! ( matches!(
739+ def,
740+ SymmetricDefinition :: Xor {
741+ hashing_algorithm: HashingAlgorithm :: Sha256 ,
742+ }
743+ ) ) ;
744+ }
745+
746+ // Error cases
747+ #[ test]
748+ fn symdef_unknown_algo ( ) {
749+ assert ! ( parse_symmetric_definition( "foobar-128-cfb" ) . is_err( ) ) ;
750+ }
751+
752+ #[ test]
753+ fn symdef_aes_128_with_invalid_null_mode ( ) {
754+ assert ! ( parse_symmetric_definition( "aes-128-null" ) . is_err( ) ) ;
755+ }
756+
757+ #[ test]
758+ fn symdef_sm4_cbc_with_unavailable_192_bits ( ) {
759+ assert ! ( parse_symmetric_definition( "sm4-192-cbc" ) . is_err( ) ) ;
760+ }
761+
762+ #[ test]
763+ fn symdef_empty_string ( ) {
764+ assert ! ( parse_symmetric_definition( "" ) . is_err( ) ) ;
765+ }
0 commit comments