1use serde::{Deserialize, Serialize};
2use std::str::FromStr;
3use crate::error::{Result, SpectreError};
4
5pub const SPECTRE_ALGORITHM_FIRST: u32 = 0;
6pub const SPECTRE_ALGORITHM_CURRENT: u32 = 3;
7pub const SPECTRE_ALGORITHM_LAST: u32 = 3;
8
9pub const SPECTRE_COUNTER_DEFAULT: u32 = 1;
10pub const SPECTRE_COUNTER_INITIAL: u32 = 0;
11pub const SPECTRE_COUNTER_FIRST: u32 = 0;
12pub const SPECTRE_COUNTER_LAST: u32 = u32::MAX;
13
14pub type SpectreAlgorithm = u32;
15pub type SpectreCounter = u32;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18pub enum SpectreKeyPurpose {
19 Authentication,
20 Identification,
21 Recovery,
22}
23
24impl SpectreKeyPurpose {
25 pub fn name(&self) -> &'static str {
26 match self {
27 Self::Authentication => "authentication",
28 Self::Identification => "identification",
29 Self::Recovery => "recovery",
30 }
31 }
32}
33
34impl FromStr for SpectreKeyPurpose {
35 type Err = SpectreError;
36
37 fn from_str(s: &str) -> Result<Self> {
38 match s {
39 "a" | "auth" | "authentication" => Ok(Self::Authentication),
40 "i" | "ident" | "identification" => Ok(Self::Identification),
41 "r" | "rec" | "recovery" => Ok(Self::Recovery),
42 _ => Err(SpectreError::InvalidKeyPurpose(s.to_string())),
43 }
44 }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
48#[repr(u32)]
49pub enum SpectreResultType {
50 MaximumSecurityPassword = 0x00010000,
52 LongPassword = 0x00010001,
53 MediumPassword = 0x00010002,
54 BasicPassword = 0x00010004,
55 ShortPassword = 0x00010003,
56 PIN = 0x00010005,
57 Name = 0x00010006,
58 Phrase = 0x00010007,
59
60 PersonalPassword = 0x00020000,
62 DeriveKey = 0x00020001,
63
64 #[default]
65 None = 0x0,
66}
67
68impl SpectreResultType {
69 pub fn short_name(&self) -> &'static str {
70 match self {
71 Self::MaximumSecurityPassword => "maximum",
72 Self::LongPassword => "long",
73 Self::MediumPassword => "medium",
74 Self::BasicPassword => "basic",
75 Self::ShortPassword => "short",
76 Self::PIN => "pin",
77 Self::Name => "name",
78 Self::Phrase => "phrase",
79 Self::DeriveKey => "key",
80 Self::PersonalPassword => "personal",
81 Self::None => "none",
82 }
83 }
84
85 pub fn is_stateful(&self) -> bool {
86 matches!(self, Self::PersonalPassword | Self::DeriveKey)
87 }
88
89 pub fn template(&self) -> &'static [&'static str] {
90 match self {
91 Self::MaximumSecurityPassword => &[
92 "anoxxxxxxxxxxxxxxxxx",
93 "axxxxxxxxxxxxxxxxxno",
94 ],
95 Self::LongPassword => &[
96 "CvcvnoCvcvCvcv",
97 "CvcvCvcvnoCvcv",
98 "CvcvCvcvCvcvno",
99 "CvccnoCvcvCvcv",
100 "CvccCvcvnoCvcv",
101 "CvccCvcvCvcvno",
102 "CvcvnoCvccCvcv",
103 "CvcvCvccnoCvcv",
104 "CvcvCvccCvcvno",
105 "CvcvnoCvcvCvcc",
106 "CvcvCvcvnoCvcc",
107 "CvcvCvcvCvccno",
108 "CvccnoCvccCvcv",
109 "CvccCvccnoCvcv",
110 "CvccCvccCvcvno",
111 "CvcvnoCvccCvcc",
112 "CvcvCvccnoCvcc",
113 "CvcvCvccCvccno",
114 "CvccnoCvcvCvcc",
115 "CvccCvcvnoCvcc",
116 "CvccCvcvCvccno",
117 ],
118 Self::MediumPassword => &[
119 "CvcnoCvc",
120 "CvcCvcno",
121 ],
122 Self::BasicPassword => &[
123 "aaanaaan",
124 "aannaaan",
125 "aaannaaa",
126 ],
127 Self::ShortPassword => &[
128 "Cvcn",
129 ],
130 Self::PIN => &[
131 "nnnn",
132 ],
133 Self::Name => &[
134 "cvccvcvcv",
135 ],
136 Self::Phrase => &[
137 "cvcc cvc cvccvcv cvc",
138 "cvc cvccvcvcv cvcv",
139 "cv cvccv cvc cvcvccv",
140 ],
141 _ => &[],
142 }
143 }
144}
145
146impl FromStr for SpectreResultType {
147 type Err = SpectreError;
148
149 fn from_str(s: &str) -> Result<Self> {
150 match s {
151 "x" | "max" | "maximum" => Ok(Self::MaximumSecurityPassword),
152 "l" | "long" => Ok(Self::LongPassword),
153 "m" | "medium" => Ok(Self::MediumPassword),
154 "b" | "basic" => Ok(Self::BasicPassword),
155 "s" | "short" => Ok(Self::ShortPassword),
156 "i" | "pin" => Ok(Self::PIN),
157 "n" | "name" => Ok(Self::Name),
158 "p" | "phrase" => Ok(Self::Phrase),
159 "K" | "key" => Ok(Self::DeriveKey),
160 "P" | "personal" => Ok(Self::PersonalPassword),
161 _ => Err(SpectreError::InvalidResultType(s.to_string())),
162 }
163 }
164}
165
166pub const SPECTRE_RESULT_DEFAULT_RESULT: SpectreResultType = SpectreResultType::LongPassword;
167
168pub fn char_class_for_template(c: char) -> &'static [char] {
170 match c {
171 'V' => &['A', 'E', 'I', 'O', 'U'],
172 'C' => &['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z'],
173 'v' => &['a', 'e', 'i', 'o', 'u'],
174 'c' => &['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'],
175 'A' => &['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
176 'a' => &['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
177 'n' => &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
178 'o' => &['@', '&', '%', '?', ',', '=', '[', ']', '_', ':', '-', '+', '*', '$', '#', '!', '\'', '^', '~', ';', '(', ')', '/', '.'],
181 'x' => &['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
182 ' ' => &[' '],
183 _ => &[],
184 }
185}
186