CH-J ToolsSSH کے ذریعے سرور کا انتظام
مینو
شائع شدہ سورس

CH-J Tools

ایپلیکیشن کی کسی مخصوص ریلیز کی ڈائریکٹریز اور فائلیں دیکھیں۔

سورس ZIP ڈاؤن لوڈ کریں
CH-J / Server Manager 1704 فائلیں
0.1.2-beta شامل کیا گیا: · بلڈ کیا گیا:
algorithms.rs شامل کیا گیا: تاریخ درج نہیں 13.6 KB · 308 لائنیں
کوڈ فائل ڈاؤن لوڈ کریں
1//! Supported local hash algorithms (port of `hashing/hashAlgorithms.js`, same ids and order).
3use crate::core::error::{CoreError, CoreResult};
4use serde_json::{json, Map, Value};
6#[derive(Debug, Clone, Copy)]
7pub struct Xof {
8 pub default_bytes: usize,
9 pub min_bytes: usize,
10 pub max_bytes: usize,
13#[derive(Debug, Clone, Copy)]
14pub struct Algorithm {
15 pub id: &'static str,
16 pub name: &'static str,
17 pub category: &'static str,
18 pub digest_bits: Option<u32>,
19 pub xof: Option<Xof>,
20 pub seed_bits: Option<u32>,
21 pub key_bytes: Option<usize>,
22 pub random_access: bool,
23 pub parameters: Option<&'static str>,
26const fn alg(id: &'static str, name: &'static str, category: &'static str, bits: u32) -> Algorithm {
27 Algorithm { id, name, category, digest_bits: Some(bits), xof: None, seed_bits: None, key_bytes: None, random_access: false, parameters: None }
29const fn xof(id: &'static str, name: &'static str, default_bytes: usize) -> Algorithm {
30 Algorithm { digest_bits: None, xof: Some(Xof { default_bytes, min_bytes: 16, max_bytes: 1024 }), ..alg(id, name, "xof", 0) }
32const fn seeded(id: &'static str, name: &'static str, bits: u32, seed_bits: u32) -> Algorithm {
33 Algorithm { seed_bits: Some(seed_bits), ..alg(id, name, "fast", bits) }
35const fn random(id: &'static str, name: &'static str, bits: u32) -> Algorithm {
36 Algorithm { random_access: true, ..alg(id, name, "fast", bits) }
38const fn keyed(id: &'static str, name: &'static str, bits: u32, key_bytes: usize) -> Algorithm {
39 Algorithm { key_bytes: Some(key_bytes), ..alg(id, name, "fast", bits) }
41const fn crc(id: &'static str, name: &'static str, bits: u32, parameters: &'static str) -> Algorithm {
42 Algorithm { parameters: Some(parameters), ..alg(id, name, "checksums", bits) }
45pub const ALGORITHMS: [Algorithm; 49] = [
46 alg("sha224", "SHA-224", "legacy", 224),
47 alg("sha256", "SHA-256", "recommended", 256),
48 alg("sha384", "SHA-384", "recommended", 384),
49 alg("sha512", "SHA-512", "recommended", 512),
50 alg("sha512-224", "SHA-512/224", "recommended", 224),
51 alg("sha512-256", "SHA-512/256", "recommended", 256),
52 alg("sha3-224", "SHA3-224", "recommended", 224),
53 alg("sha3-256", "SHA3-256", "recommended", 256),
54 alg("sha3-384", "SHA3-384", "recommended", 384),
55 alg("sha3-512", "SHA3-512", "recommended", 512),
56 xof("shake128", "SHAKE128", 32),
57 xof("shake256", "SHAKE256", 64),
58 alg("blake2b-512", "BLAKE2b-512", "recommended", 512),
59 alg("blake2s-256", "BLAKE2s-256", "recommended", 256),
60 alg("blake3", "BLAKE3", "recommended", 256),
61 xof("kangaroo-twelve", "KangarooTwelve", 32),
62 alg("ripemd160", "RIPEMD-160", "legacy", 160),
63 alg("whirlpool", "Whirlpool", "legacy", 512),
64 alg("tiger", "Tiger", "legacy", 192),
65 alg("tiger2", "Tiger2", "legacy", 192),
66 alg("md5", "MD5", "broken", 128),
67 alg("sha1", "SHA-1", "broken", 160),
68 seeded("xxh32", "XXH32", 32, 32),
69 seeded("xxh64", "XXH64", 64, 64),
70 seeded("xxh3-64", "XXH3-64", 64, 64),
71 seeded("xxh3-128", "XXH3-128", 128, 64),
72 seeded("murmur3-x86-32", "MurmurHash3 x86 32", 32, 32),
73 seeded("murmur3-x86-128", "MurmurHash3 x86 128", 128, 32),
74 seeded("murmur3-x64-128", "MurmurHash3 x64 128", 128, 32),
75 random("cityhash32", "CityHash32", 32),
76 random("cityhash64", "CityHash64", 64),
77 random("cityhash128", "CityHash128", 128),
78 random("farmhash32", "FarmHash32", 32),
79 random("farmhash64", "FarmHash64", 64),
80 random("farmhash128", "FarmHash128", 128),
81 keyed("highwayhash64", "HighwayHash64", 64, 32),
82 keyed("highwayhash128", "HighwayHash128", 128, 32),
83 keyed("highwayhash256", "HighwayHash256", 256, 32),
84 keyed("siphash-2-4", "SipHash-2-4", 64, 16),
85 alg("fnv1-32", "FNV-1 32", "fast", 32),
86 alg("fnv1-64", "FNV-1 64", "fast", 64),
87 alg("fnv1a-32", "FNV-1a 32", "fast", 32),
88 alg("fnv1a-64", "FNV-1a 64", "fast", 64),
89 crc("crc16-ccitt-false", "CRC-16/CCITT-FALSE", 16, "poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000"),
90 crc("crc32", "CRC-32/ISO-HDLC", 32, "poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff"),
91 crc("crc32c", "CRC-32C/Castagnoli", 32, "poly=0x1edc6f41 init=0xffffffff refin=true refout=true xorout=0xffffffff"),
92 crc("crc64-ecma", "CRC-64/ECMA-182", 64, "poly=0x42f0e1eba9ea3693 init=0 refin=false refout=false xorout=0"),
93 crc("crc64-xz", "CRC-64/XZ", 64, "poly=0x42f0e1eba9ea3693 init=all-ones refin=true refout=true xorout=all-ones"),
94 alg("adler32", "Adler-32", "checksums", 32),
95];
97pub fn by_id(id: &str) -> Option<&'static Algorithm> {
98 ALGORITHMS.iter().find(|a| a.id == id)
101fn category_name(category: &str) -> &'static str {
102 match category {
103 "recommended" => "Recommended / Cryptographic",
104 "xof" => "XOF",
105 "legacy" => "Legacy Cryptographic",
106 "broken" => "Broken / Compatibility only",
107 "fast" => "Fast non-cryptographic",
108 _ => "Checksums",
109 }
112pub fn typed(code: &str, message: impl Into<String>) -> CoreError {
113 CoreError::new(code, message)
116impl Algorithm {
117 pub fn public(&self) -> Value {
118 let mut map = Map::new();
119 map.insert("id".into(), json!(self.id));
120 map.insert("name".into(), json!(self.name));
121 map.insert("category".into(), json!(self.category));
122 map.insert("categoryName".into(), json!(category_name(self.category)));
123 map.insert("digestBits".into(), json!(self.digest_bits));
124 map.insert("backend".into(), json!("rust-core"));
125 map.insert("cryptographic".into(), json!(matches!(self.category, "recommended" | "xof" | "legacy" | "broken")));
126 map.insert(
127 "securityStatus".into(),
128 json!(match self.category {
129 "broken" => "broken",
130 "fast" | "checksums" => "non-cryptographic",
131 _ => "cryptographic",
132 }),
133 );
134 map.insert("supportsStreaming".into(), json!(!self.random_access));
135 if let Some(x) = self.xof {
136 map.insert("xof".into(), json!({ "defaultBytes": x.default_bytes, "minBytes": x.min_bytes, "maxBytes": x.max_bytes }));
137 }
138 if let Some(bits) = self.seed_bits {
139 map.insert("seeded".into(), json!(true));
140 map.insert("seedBits".into(), json!(bits));
141 }
142 if let Some(bytes) = self.key_bytes {
143 map.insert("keyed".into(), json!(true));
144 map.insert("keyBytes".into(), json!(bytes));
145 }
146 if self.random_access {
147 map.insert("randomAccess".into(), json!(true));
148 }
149 if let Some(p) = self.parameters {
150 map.insert("parameters".into(), json!(p));
151 }
152 Value::Object(map)
153 }
155 pub fn output_bytes(&self, request: &Request) -> usize {
156 request.output_bytes.unwrap_or_else(|| self.digest_bits.unwrap_or(0) as usize / 8)
157 }
160pub fn public_list() -> Value {
161 Value::Array(ALGORITHMS.iter().map(Algorithm::public).collect())
164/// Normalized algorithm request (`{id, outputBytes?, seed?, keyHex?, defaultKey?}`).
165#[derive(Debug, Clone, PartialEq)]
166pub struct Request {
167 pub id: &'static str,
168 pub output_bytes: Option<usize>,
169 pub seed: Option<u64>,
170 pub key: Option<Vec<u8>>,
171 pub default_key: bool,
174impl Request {
175 pub fn algorithm(&self) -> &'static Algorithm {
176 by_id(self.id).expect("normalized request")
177 }
179 pub fn public(&self) -> Value {
180 let mut map = Map::new();
181 map.insert("id".into(), json!(self.id));
182 if let Some(bytes) = self.output_bytes {
183 map.insert("outputBytes".into(), json!(bytes));
184 }
185 if let Some(seed) = self.seed {
186 map.insert("seed".into(), json!(seed.to_string()));
187 }
188 if let Some(key) = &self.key {
189 map.insert("keyHex".into(), json!(hex::encode(key)));
190 map.insert("defaultKey".into(), json!(self.default_key));
191 }
192 Value::Object(map)
193 }
195 pub fn simple(id: &'static str) -> Self {
196 Request { id, output_bytes: None, seed: None, key: None, default_key: false }
197 }
200fn normalize_seed(value: Option<&Value>, bits: u32) -> CoreResult<u64> {
201 let source = match value {
202 None | Some(Value::Null) => return Ok(0),
203 Some(Value::String(s)) => s.trim().to_string(),
204 Some(Value::Number(n)) => n.to_string(),
205 Some(other) => other.to_string(),
206 };
207 if source.is_empty() {
208 return Ok(0);
209 }
210 let invalid = || typed("HASH_INVALID_SEED", "Seed must be an unsigned decimal or 0x-prefixed hexadecimal integer.");
211 let parsed: u128 = if let Some(hex) = source.strip_prefix("0x").or_else(|| source.strip_prefix("0X")) {
212 if hex.is_empty() || !hex.chars().all(|c| c.is_ascii_hexdigit()) {
213 return Err(invalid());
214 }
215 let trimmed = hex.trim_start_matches('0');
216 if trimmed.len() > 32 {
217 return Err(typed("HASH_INVALID_SEED", format!("Seed must fit in {bits} bits.")));
218 }
219 u128::from_str_radix(if trimmed.is_empty() { "0" } else { trimmed }, 16).map_err(|_| invalid())?
220 } else {
221 if !source.chars().all(|c| c.is_ascii_digit()) {
222 return Err(invalid());
223 }
224 let trimmed = source.trim_start_matches('0');
225 if trimmed.len() > 38 {
226 return Err(typed("HASH_INVALID_SEED", format!("Seed must fit in {bits} bits.")));
227 }
228 if trimmed.is_empty() { 0 } else { trimmed.parse().map_err(|_| invalid())? }
229 };
230 if parsed >= (1u128 << bits) {
231 return Err(typed("HASH_INVALID_SEED", format!("Seed must fit in {bits} bits.")));
232 }
233 Ok(parsed as u64)
236pub fn normalize_requests(input: &Value) -> CoreResult<Vec<Request>> {
237 let list = input.as_array().filter(|l| !l.is_empty() && l.len() <= ALGORITHMS.len()).ok_or_else(|| typed("HASH_INVALID_ALGORITHMS", "Select between one and all supported algorithms."))?;
238 let mut seen: Vec<&str> = Vec::new();
239 let mut out = Vec::new();
240 for source in list {
241 let id = match source {
242 Value::String(s) => s.as_str(),
243 Value::Object(o) => o.get("id").and_then(Value::as_str).unwrap_or(""),
244 _ => "",
245 };
246 let algorithm = by_id(id).filter(|a| !seen.contains(&a.id)).ok_or_else(|| typed("HASH_UNSUPPORTED_ALGORITHM", format!("Unsupported or duplicate algorithm: {}", if id.is_empty() { "<empty>" } else { id })))?;
247 seen.push(algorithm.id);
248 let mut request = Request::simple(algorithm.id);
249 if let Some(x) = algorithm.xof {
250 let raw = source.get("outputBytes").filter(|v| !v.is_null());
251 let value = match raw {
252 None => Some(x.default_bytes as f64),
253 Some(Value::Number(n)) => n.as_f64(),
254 Some(Value::String(s)) => if s.trim().is_empty() { Some(0.0) } else { s.trim().parse::<f64>().ok() },
255 Some(Value::Bool(b)) => Some(if *b { 1.0 } else { 0.0 }),
256 _ => None,
257 };
258 match value {
259 Some(v) if v.fract() == 0.0 && v >= x.min_bytes as f64 && v <= x.max_bytes as f64 => request.output_bytes = Some(v as usize),
260 _ => return Err(typed("HASH_INVALID_XOF_LENGTH", format!("{} output must be {}-{} bytes.", algorithm.name, x.min_bytes, x.max_bytes))),
261 }
262 }
263 if let Some(bits) = algorithm.seed_bits {
264 request.seed = Some(normalize_seed(source.get("seed"), bits)?);
265 }
266 if let Some(bytes) = algorithm.key_bytes {
267 let provided = source.get("keyHex").and_then(|v| match v {
268 Value::String(s) if !s.is_empty() => Some(s.trim().to_lowercase()),
269 Value::Null | Value::Bool(false) => None,
270 Value::String(_) => None,
271 other => Some(other.to_string()),
272 });
273 let key_hex = provided.clone().unwrap_or_else(|| "00".repeat(bytes));
274 if key_hex.len() != bytes * 2 || !key_hex.chars().all(|c| c.is_ascii_digit() || ('a'..='f').contains(&c)) {
275 return Err(typed("HASH_INVALID_KEY", format!("{} key must be exactly {bytes} bytes in hexadecimal.", algorithm.name)));
276 }
277 request.key = Some(hex::decode(&key_hex).map_err(|_| typed("HASH_INVALID_KEY", "Invalid key."))?);
278 request.default_key = provided.is_none();
279 }
280 out.push(request);
281 }
282 Ok(out)
285#[cfg(test)]
286mod tests {
287 use super::*;
289 #[test]
290 fn normalizes_like_0_1_0() {
291 assert_eq!(ALGORITHMS.len(), 49);
292 let r = normalize_requests(&json!(["sha256", {"id": "shake128"}, {"id": "xxh64", "seed": "0x10"}, {"id": "siphash-2-4"}])).unwrap();
293 assert_eq!(r[1].output_bytes, Some(32));
294 assert_eq!(r[2].seed, Some(16));
295 assert_eq!(r[3].key.as_deref(), Some(&[0u8; 16][..]));
296 assert!(r[3].default_key);
297 assert_eq!(normalize_requests(&json!(["sha256", "sha256"])).unwrap_err().code, "HASH_UNSUPPORTED_ALGORITHM");
298 assert_eq!(normalize_requests(&json!([])).unwrap_err().code, "HASH_INVALID_ALGORITHMS");
299 assert_eq!(normalize_requests(&json!([{"id": "xxh32", "seed": "4294967296"}])).unwrap_err().code, "HASH_INVALID_SEED");
300 assert_eq!(normalize_requests(&json!([{"id": "xxh32", "seed": "-1"}])).unwrap_err().code, "HASH_INVALID_SEED");
301 assert_eq!(normalize_requests(&json!([{"id": "shake256", "outputBytes": 8}])).unwrap_err().code, "HASH_INVALID_XOF_LENGTH");
302 assert_eq!(normalize_requests(&json!([{"id": "highwayhash64", "keyHex": "zz"}])).unwrap_err().code, "HASH_INVALID_KEY");
303 let list = public_list();
304 assert_eq!(list[0]["categoryName"], "Legacy Cryptographic");
305 assert_eq!(list[10]["xof"]["defaultBytes"], 32);
306 assert!(list[0].get("xof").is_none());
307 }
SHA-25630751015ff3a553e56f3c93c33176a4bc895fa8a7fa489468f22a5737beab929

CH-J Proprietary Software License 1.14 · سورس CH-J Proprietary Software License 1.14 کے تحت فراہم کیا جاتا ہے۔ اس کی دستیابی لائسنس کی شرائط نہیں بدلتی اور نہ ہی اضافی حقوق دیتی ہے۔

آرکائیو کا SHA-256ac8fe790f4ba60fc098f8c985fc2656cfcc6cdc21fb34b30e308a2b54e62258f
فائلیں