1use super::{arg_str, to_base64, to_hex};
13use crate::host::{is_callable, with_host, JsObj};
14use cipher::block_padding::Pkcs7;
15use cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
16use fusevm::Value;
17use hkdf::Hkdf;
18use hmac::{Hmac, Mac};
19use indexmap::IndexMap;
20use md5::{Digest as _, Md5};
21use num_bigint::BigUint;
22use p256::elliptic_curve::sec1::ToEncodedPoint;
23use pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding};
24use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey};
25use sha1::Sha1;
26use sha2::{Sha256, Sha384, Sha512};
27use signature::{SignatureEncoding, Signer, Verifier};
28use spki::{DecodePublicKey, EncodePublicKey};
29use subtle::ConstantTimeEq;
30
31const CIPHERS: &[&str] = &[
33 "aes-128-cbc",
34 "aes-192-cbc",
35 "aes-256-cbc",
36 "aes-128-ctr",
37 "aes-192-ctr",
38 "aes-256-ctr",
39];
40
41const HASHES: &[&str] = &["md5", "sha1", "sha256", "sha512"];
43
44const CURVES: &[&str] = &[
48 "prime256v1",
49 "secp256k1",
50 "secp384r1",
51 "secp521r1",
52 "secp224r1",
53 "secp192k1",
54 "secp256r1",
55];
56
57pub const METHODS: &[&str] = &[
58 "createHash",
59 "createHmac",
60 "randomBytes",
61 "randomUUID",
62 "randomInt",
63 "pbkdf2Sync",
64 "pbkdf2",
65 "scryptSync",
66 "scrypt",
67 "hkdfSync",
68 "hkdf",
69 "createCipheriv",
70 "createDecipheriv",
71 "randomFillSync",
72 "randomFill",
73 "timingSafeEqual",
74 "getHashes",
75 "getCiphers",
76 "getCurves",
77 "getFips",
78 "pseudoRandomBytes",
79 "prng",
80 "rng",
81 "hash",
82 "randomUUIDv7",
83 "getCipherInfo",
84 "generateKeyPairSync",
86 "generateKeyPair",
87 "createPrivateKey",
88 "createPublicKey",
89 "createSecretKey",
90 "createSign",
91 "createVerify",
92 "sign",
93 "verify",
94 "publicEncrypt",
95 "privateDecrypt",
96 "privateEncrypt",
97 "publicDecrypt",
98 "createDiffieHellman",
100 "createDiffieHellmanGroup",
101 "getDiffieHellman",
102 "createECDH",
103 "diffieHellman",
104 "checkPrime",
106 "checkPrimeSync",
107 "generatePrime",
108 "generatePrimeSync",
109 "argon2",
111 "argon2Sync",
112 "getRandomValues",
113];
114
115pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
116 Some(match method {
117 "createHash" => {
118 let algo = arg_str(args, 0).to_ascii_lowercase();
119 if !supported(&algo) {
120 return Some(Err(format!("Error: Digest method not supported: {algo}")));
121 }
122 Ok(with_host(|h| {
123 let data = h.new_array(Vec::new());
124 let mut m = IndexMap::new();
125 m.insert("@@native".into(), h.new_str("Hash"));
126 m.insert("@@algo".into(), h.new_str(algo));
127 m.insert("@@data".into(), data);
128 h.new_object(m)
129 }))
130 }
131 "createHmac" => {
132 let algo = arg_str(args, 0).to_ascii_lowercase();
133 if !supported(&algo) {
134 return Some(Err(format!("Error: Digest method not supported: {algo}")));
135 }
136 let key = key_bytes(args.get(1));
138 Ok(with_host(|h| {
139 let data = h.new_array(Vec::new());
140 let keyv = h.new_array(key.iter().map(|b| Value::Float(*b as f64)).collect());
141 let mut m = IndexMap::new();
142 m.insert("@@native".into(), h.new_str("Hmac"));
143 m.insert("@@algo".into(), h.new_str(algo));
144 m.insert("@@key".into(), keyv);
145 m.insert("@@data".into(), data);
146 h.new_object(m)
147 }))
148 }
149 "randomBytes" => {
150 let n = super::arg_num(args, 0).max(0.0) as usize;
151 let mut buf = vec![0u8; n];
152 if let Err(e) = getrandom::getrandom(&mut buf) {
153 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
154 }
155 let cb = args
158 .get(1)
159 .cloned()
160 .filter(|v| with_host(|h| is_callable(h, v)));
161 if let Some(cb) = cb {
162 let bufv = super::buffer::from_bytes(&buf);
163 with_host(|h| {
164 let nullv = h.null();
165 h.queue_micro(cb, vec![nullv, bufv]);
166 });
167 Ok(Value::Undef)
168 } else {
169 Ok(super::buffer::from_bytes(&buf))
170 }
171 }
172 "randomUUID" => {
173 let mut b = [0u8; 16];
174 if let Err(e) = getrandom::getrandom(&mut b) {
175 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
176 }
177 b[6] = (b[6] & 0x0f) | 0x40;
179 b[8] = (b[8] & 0x3f) | 0x80;
180 let h = to_hex(&b);
181 let uuid = format!(
182 "{}-{}-{}-{}-{}",
183 &h[0..8],
184 &h[8..12],
185 &h[12..16],
186 &h[16..20],
187 &h[20..32],
188 );
189 Ok(with_host(|host| host.new_str(uuid)))
190 }
191 "randomInt" => {
192 let (min, max) = if args.len() >= 2 {
194 (super::arg_num(args, 0), super::arg_num(args, 1))
195 } else {
196 (0.0, super::arg_num(args, 0))
197 };
198 let (min, max) = (min as i64, max as i64);
199 if max <= min {
200 return Some(Err("Error: The value of \"max\" is out of range. It must be greater than the value of \"min\".".into()));
201 }
202 let range = (max - min) as u64;
203 match random_below(range) {
204 Ok(r) => Ok(Value::Float((min + r as i64) as f64)),
205 Err(e) => Err(format!("Error: failed to generate random bytes: {e}")),
206 }
207 }
208 "pbkdf2Sync" => {
210 let digest = arg_str(args, 4).to_ascii_lowercase();
211 match pbkdf2_derive(
212 &digest,
213 &val_bytes_at(args, 0),
214 &val_bytes_at(args, 1),
215 super::arg_num(args, 2) as u32,
216 super::arg_num(args, 3).max(0.0) as usize,
217 ) {
218 Ok(out) => Ok(super::buffer::from_bytes(&out)),
219 Err(e) => Err(e),
220 }
221 }
222 "pbkdf2" => {
223 let digest = arg_str(args, 4).to_ascii_lowercase();
224 let res = pbkdf2_derive(
225 &digest,
226 &val_bytes_at(args, 0),
227 &val_bytes_at(args, 1),
228 super::arg_num(args, 2) as u32,
229 super::arg_num(args, 3).max(0.0) as usize,
230 );
231 deliver_async(args.get(5).cloned(), res)
232 }
233 "scryptSync" => {
234 let keylen = super::arg_num(args, 2).max(0.0) as usize;
235 match scrypt_derive(
236 &val_bytes_at(args, 0),
237 &val_bytes_at(args, 1),
238 keylen,
239 opts_object(args, 3),
240 ) {
241 Ok(out) => Ok(super::buffer::from_bytes(&out)),
242 Err(e) => Err(e),
243 }
244 }
245 "scrypt" => {
246 let keylen = super::arg_num(args, 2).max(0.0) as usize;
247 let res = scrypt_derive(
248 &val_bytes_at(args, 0),
249 &val_bytes_at(args, 1),
250 keylen,
251 opts_object(args, 3),
252 );
253 deliver_async(trailing_cb(args), res)
254 }
255 "hkdfSync" => {
256 let digest = arg_str(args, 0).to_ascii_lowercase();
257 match hkdf_derive(
258 &digest,
259 &val_bytes_at(args, 1),
260 &val_bytes_at(args, 2),
261 &val_bytes_at(args, 3),
262 super::arg_num(args, 4).max(0.0) as usize,
263 ) {
264 Ok(out) => Ok(super::buffer::from_bytes(&out)),
265 Err(e) => Err(e),
266 }
267 }
268 "hkdf" => {
269 let digest = arg_str(args, 0).to_ascii_lowercase();
270 let res = hkdf_derive(
271 &digest,
272 &val_bytes_at(args, 1),
273 &val_bytes_at(args, 2),
274 &val_bytes_at(args, 3),
275 super::arg_num(args, 4).max(0.0) as usize,
276 );
277 deliver_async(args.get(5).cloned(), res)
278 }
279 "createCipheriv" => make_cipher("Cipheriv", args),
281 "createDecipheriv" => make_cipher("Decipheriv", args),
282 "randomFillSync" => random_fill(args),
284 "randomFill" => {
285 let cb = trailing_cb(args);
286 let res = random_fill(args);
287 match (cb, res) {
288 (Some(cb), Ok(buf)) => {
289 with_host(|h| {
290 let nullv = h.null();
291 h.queue_micro(cb, vec![nullv, buf]);
292 });
293 Ok(Value::Undef)
294 }
295 (Some(cb), Err(e)) => {
296 let errv = with_host(|h| h.new_str(e));
297 with_host(|h| h.queue_micro(cb, vec![errv]));
298 Ok(Value::Undef)
299 }
300 (None, r) => r,
301 }
302 }
303 "timingSafeEqual" => {
305 let a = val_bytes_at(args, 0);
306 let b = val_bytes_at(args, 1);
307 if a.len() != b.len() {
308 return Some(Err(
309 "Error: Input buffers must have the same byte length".into()
310 ));
311 }
312 Ok(Value::Bool(a.ct_eq(&b).into()))
313 }
314 "getHashes" => Ok(with_host(|h| {
316 let items: Vec<Value> = HASHES.iter().map(|s| h.new_str(*s)).collect();
317 h.new_array(items)
318 })),
319 "getCiphers" => Ok(with_host(|h| {
320 let items: Vec<Value> = CIPHERS.iter().map(|s| h.new_str(*s)).collect();
321 h.new_array(items)
322 })),
323 "getCurves" => Ok(with_host(|h| {
324 let items: Vec<Value> = CURVES.iter().map(|s| h.new_str(*s)).collect();
325 h.new_array(items)
326 })),
327 "getFips" => Ok(Value::Float(0.0)),
329 "getCipherInfo" => cipher_info(&arg_str(args, 0).to_ascii_lowercase()),
330 "pseudoRandomBytes" | "prng" | "rng" => {
332 let n = super::arg_num(args, 0).max(0.0) as usize;
333 let mut buf = vec![0u8; n];
334 if let Err(e) = getrandom::getrandom(&mut buf) {
335 return Some(Err(format!("Error: failed to generate random bytes: {e}")));
336 }
337 let cb = args
338 .get(1)
339 .cloned()
340 .filter(|v| with_host(|h| is_callable(h, v)));
341 if let Some(cb) = cb {
342 let bufv = super::buffer::from_bytes(&buf);
343 with_host(|h| {
344 let nullv = h.null();
345 h.queue_micro(cb, vec![nullv, bufv]);
346 });
347 Ok(Value::Undef)
348 } else {
349 Ok(super::buffer::from_bytes(&buf))
350 }
351 }
352 "hash" => {
354 let algo = arg_str(args, 0).to_ascii_lowercase();
355 if !supported(&algo) {
356 return Some(Err(format!("Error: Digest method not supported: {algo}")));
357 }
358 let data = val_bytes_at(args, 1);
360 let out = digest(&algo, &data);
362 let out_enc = if args.len() > 2 {
363 arg_str(args, 2)
364 } else {
365 "hex".into()
366 };
367 Ok(if out_enc == "buffer" {
368 super::buffer::from_bytes(&out)
369 } else {
370 encode_out(&out, Some(&out_enc))
371 })
372 }
373 "randomUUIDv7" => uuid_v7(),
375 "generateKeyPairSync" => {
377 generate_key_pair(&arg_str(args, 0).to_ascii_lowercase(), args.get(1))
378 }
379 "generateKeyPair" => {
380 let cb = trailing_cb(args);
381 let res = generate_key_pair(&arg_str(args, 0).to_ascii_lowercase(), args.get(1));
382 match cb {
383 Some(cb) => {
384 match res {
385 Ok(pair) => with_host(|h| {
386 let nullv = h.null();
388 let (pubk, prvk) = match h.get(&pair) {
389 Some(JsObj::Object(p)) => (
390 p.get("publicKey").cloned().unwrap_or(Value::Undef),
391 p.get("privateKey").cloned().unwrap_or(Value::Undef),
392 ),
393 _ => (Value::Undef, Value::Undef),
394 };
395 h.queue_micro(cb, vec![nullv, pubk, prvk]);
396 }),
397 Err(e) => {
398 let errv = with_host(|h| h.new_str(e));
399 with_host(|h| h.queue_micro(cb, vec![errv]));
400 }
401 }
402 Ok(Value::Undef)
403 }
404 None => res,
405 }
406 }
407 "createPrivateKey" => create_private_key(args.first()),
408 "createPublicKey" => create_public_key(args.first()),
409 "createSecretKey" => Ok(secret_key_object(&val_bytes_at(args, 0))),
410 "createSign" => Ok(new_sign_verify("Sign", &arg_str(args, 0))),
412 "createVerify" => Ok(new_sign_verify("Verify", &arg_str(args, 0))),
413 "sign" => {
415 let algo = arg_str(args, 0);
416 let data = val_bytes_at(args, 1);
417 let key = key_material(args.get(2).unwrap_or(&Value::Undef));
418 match sign_data(&key, &algo, &data) {
419 Ok(sig) => Ok(super::buffer::from_bytes(&sig)),
420 Err(e) => Err(e),
421 }
422 }
423 "verify" => {
424 let algo = arg_str(args, 0);
425 let data = val_bytes_at(args, 1);
426 let key = key_material(args.get(2).unwrap_or(&Value::Undef));
427 let sig = val_bytes_at(args, 3);
428 match verify_data(&key, &algo, &data, &sig) {
429 Ok(ok) => Ok(Value::Bool(ok)),
430 Err(e) => Err(e),
431 }
432 }
433 "publicEncrypt" => rsa_public_op(args, true, true),
435 "privateDecrypt" => rsa_public_op(args, false, false),
436 "privateEncrypt" => rsa_private_encrypt(args),
437 "publicDecrypt" => rsa_public_decrypt(args),
438 "createDiffieHellman" => create_diffie_hellman(args),
440 "createDiffieHellmanGroup" | "getDiffieHellman" => diffie_hellman_group(&arg_str(args, 0)),
441 "createECDH" => create_ecdh(&arg_str(args, 0)),
442 "diffieHellman" => diffie_hellman_oneshot(args.first()),
443 "checkPrimeSync" => Ok(Value::Bool(check_prime(args.first()))),
445 "checkPrime" => {
446 let ok = check_prime(args.first());
447 let cb = trailing_cb(args);
448 match cb {
449 Some(cb) => {
450 with_host(|h| {
451 let nullv = h.null();
452 h.queue_micro(cb, vec![nullv, Value::Bool(ok)]);
453 });
454 Ok(Value::Undef)
455 }
456 None => Ok(Value::Bool(ok)),
457 }
458 }
459 "generatePrimeSync" => {
460 generate_prime(super::arg_num(args, 0) as usize, opts_object(args, 1))
461 }
462 "generatePrime" => {
463 let res = generate_prime(super::arg_num(args, 0) as usize, opts_object(args, 1));
464 let cb = trailing_cb(args);
465 match (cb, res) {
466 (Some(cb), Ok(v)) => {
467 with_host(|h| {
468 let nullv = h.null();
469 h.queue_micro(cb, vec![nullv, v]);
470 });
471 Ok(Value::Undef)
472 }
473 (Some(cb), Err(e)) => {
474 let errv = with_host(|h| h.new_str(e));
475 with_host(|h| h.queue_micro(cb, vec![errv]));
476 Ok(Value::Undef)
477 }
478 (None, r) => r,
479 }
480 }
481 "argon2Sync" => match argon2_hash(&arg_str(args, 0), args.get(1)) {
483 Ok(out) => Ok(super::buffer::from_bytes(&out)),
484 Err(e) => Err(e),
485 },
486 "argon2" => deliver_async(
487 trailing_cb(args),
488 argon2_hash(&arg_str(args, 0), args.get(1)),
489 ),
490 "getRandomValues" => get_random_values(args.first()),
492 _ => return None,
493 })
494}
495
496pub fn instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
498 hashlike_call("Hash", recv, method, args)
499}
500
501pub fn hmac_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
503 hashlike_call("Hmac", recv, method, args)
504}
505
506pub fn cipher_instance_call(
512 tag: &str,
513 recv: &Value,
514 method: &str,
515 args: &[Value],
516) -> Result<Value, String> {
517 match method {
518 "update" => {
519 let bytes = cipher_input_bytes(args);
520 with_host(|h| {
521 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
522 if let Some(arr) = p.get("@@data").cloned() {
523 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
524 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
525 }
526 }
527 }
528 });
529 let out_enc = if args.len() > 2 {
530 Some(arg_str(args, 2))
531 } else {
532 None
533 };
534 Ok(encode_out(&[], out_enc.as_deref()))
535 }
536 "final" => {
537 let (algo, key, iv, data) = with_host(|h| {
538 let (mut algo, mut key, mut iv, mut data) =
539 (String::new(), Vec::new(), Vec::new(), Vec::new());
540 if let Some(JsObj::Object(p)) = h.get(recv) {
541 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
542 if let Some(JsObj::Array(it)) = p.get("@@key").and_then(|v| h.get(v)) {
543 key = it.iter().map(|v| h.to_number(v) as u8).collect();
544 }
545 if let Some(JsObj::Array(it)) = p.get("@@iv").and_then(|v| h.get(v)) {
546 iv = it.iter().map(|v| h.to_number(v) as u8).collect();
547 }
548 if let Some(JsObj::Array(it)) = p.get("@@data").and_then(|v| h.get(v)) {
549 data = it.iter().map(|v| h.to_number(v) as u8).collect();
550 }
551 }
552 (algo, key, iv, data)
553 });
554 let out = cipher_crypt(&algo, &key, &iv, &data, tag == "Cipheriv")?;
555 let out_enc = if args.is_empty() {
556 None
557 } else {
558 Some(arg_str(args, 0))
559 };
560 Ok(encode_out(&out, out_enc.as_deref()))
561 }
562 "setAutoPadding" => Ok(recv.clone()),
563 _ => Err(crate::host::type_error(&format!(
564 "{}.{method} is not a function",
565 tag.to_ascii_lowercase()
566 ))),
567 }
568}
569
570fn hashlike_call(kind: &str, recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
573 match method {
574 "update" => {
575 let enc = if args.len() > 1 {
576 arg_str(args, 1)
577 } else {
578 "utf8".into()
579 };
580 let bytes = decode(&arg_str(args, 0), &enc);
581 with_host(|h| {
582 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
583 if let Some(arr) = p.get("@@data").cloned() {
584 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
585 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
586 }
587 }
588 }
589 });
590 Ok(recv.clone())
591 }
592 "digest" => {
593 let (algo, key, data) = with_host(|h| {
594 let (mut algo, mut key, mut data) = (String::new(), Vec::new(), Vec::new());
595 if let Some(JsObj::Object(p)) = h.get(recv) {
596 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
597 if let Some(JsObj::Array(items)) = p.get("@@data").and_then(|v| h.get(v)) {
598 data = items.iter().map(|v| h.to_number(v) as u8).collect();
599 }
600 if let Some(JsObj::Array(items)) = p.get("@@key").and_then(|v| h.get(v)) {
601 key = items.iter().map(|v| h.to_number(v) as u8).collect();
602 }
603 }
604 (algo, key, data)
605 });
606 let out = if kind == "Hmac" {
607 hmac_digest(&algo, &key, &data)
608 } else {
609 digest(&algo, &data)
610 };
611 let enc = if args.is_empty() {
612 None
613 } else {
614 Some(arg_str(args, 0))
615 };
616 Ok(match enc.as_deref() {
617 Some("hex") => with_host(|h| h.new_str(to_hex(&out))),
618 Some("base64") | Some("base64url") => with_host(|h| h.new_str(to_base64(&out))),
619 Some("latin1") | Some("binary") => {
620 with_host(|h| h.new_str(out.iter().map(|b| *b as char).collect::<String>()))
621 }
622 _ => super::buffer::from_bytes(&out),
623 })
624 }
625 _ => Err(crate::host::type_error(&format!(
626 "{}.{method} is not a function",
627 kind.to_ascii_lowercase()
628 ))),
629 }
630}
631
632fn supported(algo: &str) -> bool {
633 matches!(algo, "md5" | "sha1" | "sha256" | "sha512")
634}
635
636fn digest(algo: &str, data: &[u8]) -> Vec<u8> {
637 match algo {
638 "md5" => {
639 let mut h = Md5::new();
640 h.update(data);
641 h.finalize().to_vec()
642 }
643 "sha1" => {
644 let mut h = Sha1::new();
645 h.update(data);
646 h.finalize().to_vec()
647 }
648 "sha512" => {
649 let mut h = Sha512::new();
650 h.update(data);
651 h.finalize().to_vec()
652 }
653 _ => {
654 let mut h = Sha256::new();
655 h.update(data);
656 h.finalize().to_vec()
657 }
658 }
659}
660
661fn hmac_digest(algo: &str, key: &[u8], data: &[u8]) -> Vec<u8> {
662 match algo {
664 "md5" => {
665 let mut m = Hmac::<Md5>::new_from_slice(key).expect("HMAC accepts any key length");
666 m.update(data);
667 m.finalize().into_bytes().to_vec()
668 }
669 "sha1" => {
670 let mut m = Hmac::<Sha1>::new_from_slice(key).expect("HMAC accepts any key length");
671 m.update(data);
672 m.finalize().into_bytes().to_vec()
673 }
674 "sha512" => {
675 let mut m = Hmac::<Sha512>::new_from_slice(key).expect("HMAC accepts any key length");
676 m.update(data);
677 m.finalize().into_bytes().to_vec()
678 }
679 _ => {
680 let mut m = Hmac::<Sha256>::new_from_slice(key).expect("HMAC accepts any key length");
681 m.update(data);
682 m.finalize().into_bytes().to_vec()
683 }
684 }
685}
686
687fn key_bytes(v: Option<&Value>) -> Vec<u8> {
690 v.map(val_bytes).unwrap_or_default()
691}
692
693fn val_bytes(v: &Value) -> Vec<u8> {
696 if super::native_tag(v).as_deref() == Some("Buffer") {
697 return with_host(|h| match h.get(v) {
698 Some(JsObj::Object(p)) => match p.get("@@bytes").and_then(|b| h.get(b)) {
699 Some(JsObj::Array(items)) => items.iter().map(|x| h.to_number(x) as u8).collect(),
700 _ => Vec::new(),
701 },
702 _ => Vec::new(),
703 });
704 }
705 with_host(|h| h.str_of(v)).into_bytes()
706}
707
708fn val_bytes_at(args: &[Value], i: usize) -> Vec<u8> {
710 args.get(i).map(val_bytes).unwrap_or_default()
711}
712
713fn trailing_cb(args: &[Value]) -> Option<Value> {
715 args.last()
716 .cloned()
717 .filter(|v| with_host(|h| is_callable(h, v)))
718}
719
720fn opts_object(args: &[Value], i: usize) -> Option<Value> {
722 let v = args.get(i)?.clone();
723 let is_obj = with_host(|h| matches!(h.get(&v), Some(JsObj::Object(_))) && !is_callable(h, &v));
724 is_obj.then_some(v)
725}
726
727fn deliver_async(cb: Option<Value>, res: Result<Vec<u8>, String>) -> Result<Value, String> {
730 match (cb.filter(|v| with_host(|h| is_callable(h, v))), res) {
731 (Some(cb), Ok(out)) => {
732 let bufv = super::buffer::from_bytes(&out);
733 with_host(|h| {
734 let nullv = h.null();
735 h.queue_micro(cb, vec![nullv, bufv]);
736 });
737 Ok(Value::Undef)
738 }
739 (Some(cb), Err(e)) => {
740 let errv = with_host(|h| h.new_str(e));
741 with_host(|h| h.queue_micro(cb, vec![errv]));
742 Ok(Value::Undef)
743 }
744 (None, Ok(out)) => Ok(super::buffer::from_bytes(&out)),
745 (None, Err(e)) => Err(e),
746 }
747}
748
749fn pbkdf2_derive(
751 digest: &str,
752 pass: &[u8],
753 salt: &[u8],
754 iters: u32,
755 keylen: usize,
756) -> Result<Vec<u8>, String> {
757 let mut out = vec![0u8; keylen];
758 match digest {
759 "sha1" => pbkdf2::pbkdf2_hmac::<Sha1>(pass, salt, iters, &mut out),
760 "sha256" => pbkdf2::pbkdf2_hmac::<Sha256>(pass, salt, iters, &mut out),
761 "sha512" => pbkdf2::pbkdf2_hmac::<Sha512>(pass, salt, iters, &mut out),
762 "md5" => pbkdf2::pbkdf2_hmac::<Md5>(pass, salt, iters, &mut out),
763 _ => return Err(format!("Error: Invalid digest: {digest}")),
764 }
765 Ok(out)
766}
767
768fn scrypt_derive(
771 pass: &[u8],
772 salt: &[u8],
773 keylen: usize,
774 opts: Option<Value>,
775) -> Result<Vec<u8>, String> {
776 let (mut n, mut r, mut p) = (16384.0f64, 8.0f64, 1.0f64);
777 if let Some(o) = opts {
778 n = opt_num(&o, &["N", "cost"], n);
779 r = opt_num(&o, &["r", "blockSize"], r);
780 p = opt_num(&o, &["p", "parallelization"], p);
781 }
782 let n = n as u64;
783 if n < 2 || (n & (n - 1)) != 0 {
784 return Err("Error: Invalid scrypt param: N must be a power of two > 1".into());
785 }
786 let params = scrypt::Params::new(n.trailing_zeros() as u8, r as u32, p as u32, keylen)
787 .map_err(|e| format!("Error: {e}"))?;
788 let mut out = vec![0u8; keylen];
789 scrypt::scrypt(pass, salt, ¶ms, &mut out).map_err(|e| format!("Error: {e}"))?;
790 Ok(out)
791}
792
793fn hkdf_derive(
795 digest: &str,
796 ikm: &[u8],
797 salt: &[u8],
798 info: &[u8],
799 keylen: usize,
800) -> Result<Vec<u8>, String> {
801 let mut out = vec![0u8; keylen];
802 let ok = match digest {
803 "sha1" => Hkdf::<Sha1>::new(Some(salt), ikm).expand(info, &mut out),
804 "sha256" => Hkdf::<Sha256>::new(Some(salt), ikm).expand(info, &mut out),
805 "sha512" => Hkdf::<Sha512>::new(Some(salt), ikm).expand(info, &mut out),
806 "md5" => Hkdf::<Md5>::new(Some(salt), ikm).expand(info, &mut out),
807 _ => return Err(format!("Error: Invalid digest: {digest}")),
808 };
809 ok.map_err(|_| "Error: Invalid key length".to_string())?;
810 Ok(out)
811}
812
813fn opt_num(obj: &Value, keys: &[&str], default: f64) -> f64 {
816 with_host(|h| {
817 if let Some(JsObj::Object(p)) = h.get(obj) {
818 for k in keys {
819 if let Some(v) = p.get(*k) {
820 let n = h.to_number(v);
821 if !n.is_nan() {
822 return n;
823 }
824 }
825 }
826 }
827 default
828 })
829}
830
831fn make_cipher(tag: &str, args: &[Value]) -> Result<Value, String> {
833 let algo = arg_str(args, 0).to_ascii_lowercase();
834 if !CIPHERS.contains(&algo.as_str()) {
835 return Err(format!("Error: Unknown cipher: {algo}"));
836 }
837 let key = val_bytes_at(args, 1);
838 let iv = val_bytes_at(args, 2);
839 let want_key = key_len(&algo);
840 if key.len() != want_key {
841 return Err("Error: Invalid key length".into());
842 }
843 if iv.len() != 16 {
844 return Err("Error: Invalid initialization vector".into());
845 }
846 Ok(with_host(|h| {
847 let keyv = h.new_array(key.iter().map(|b| Value::Float(*b as f64)).collect());
848 let ivv = h.new_array(iv.iter().map(|b| Value::Float(*b as f64)).collect());
849 let data = h.new_array(Vec::new());
850 let mut m = IndexMap::new();
851 m.insert("@@native".into(), h.new_str(tag));
852 m.insert("@@algo".into(), h.new_str(algo));
853 m.insert("@@key".into(), keyv);
854 m.insert("@@iv".into(), ivv);
855 m.insert("@@data".into(), data);
856 h.new_object(m)
857 }))
858}
859
860fn cipher_input_bytes(args: &[Value]) -> Vec<u8> {
863 if super::native_tag(args.first().unwrap_or(&Value::Undef)).as_deref() == Some("Buffer") {
864 return val_bytes_at(args, 0);
865 }
866 let enc = if args.len() > 1 {
867 arg_str(args, 1)
868 } else {
869 "utf8".into()
870 };
871 decode(&arg_str(args, 0), &enc)
872}
873
874fn cipher_crypt(
877 algo: &str,
878 key: &[u8],
879 iv: &[u8],
880 data: &[u8],
881 encrypt: bool,
882) -> Result<Vec<u8>, String> {
883 const KEYERR: &str = "Error: Invalid key length";
884 const DECERR: &str = "Error: error:1C800064:Provider routines::bad decrypt";
885 match (algo, encrypt) {
886 ("aes-128-cbc", true) => Ok(cbc::Encryptor::<aes::Aes128>::new_from_slices(key, iv)
887 .map_err(|_| KEYERR.to_string())?
888 .encrypt_padded_vec_mut::<Pkcs7>(data)),
889 ("aes-192-cbc", true) => Ok(cbc::Encryptor::<aes::Aes192>::new_from_slices(key, iv)
890 .map_err(|_| KEYERR.to_string())?
891 .encrypt_padded_vec_mut::<Pkcs7>(data)),
892 ("aes-256-cbc", true) => Ok(cbc::Encryptor::<aes::Aes256>::new_from_slices(key, iv)
893 .map_err(|_| KEYERR.to_string())?
894 .encrypt_padded_vec_mut::<Pkcs7>(data)),
895 ("aes-128-cbc", false) => cbc::Decryptor::<aes::Aes128>::new_from_slices(key, iv)
896 .map_err(|_| KEYERR.to_string())?
897 .decrypt_padded_vec_mut::<Pkcs7>(data)
898 .map_err(|_| DECERR.to_string()),
899 ("aes-192-cbc", false) => cbc::Decryptor::<aes::Aes192>::new_from_slices(key, iv)
900 .map_err(|_| KEYERR.to_string())?
901 .decrypt_padded_vec_mut::<Pkcs7>(data)
902 .map_err(|_| DECERR.to_string()),
903 ("aes-256-cbc", false) => cbc::Decryptor::<aes::Aes256>::new_from_slices(key, iv)
904 .map_err(|_| KEYERR.to_string())?
905 .decrypt_padded_vec_mut::<Pkcs7>(data)
906 .map_err(|_| DECERR.to_string()),
907 ("aes-128-ctr", _) => {
908 let mut buf = data.to_vec();
909 ctr::Ctr128BE::<aes::Aes128>::new_from_slices(key, iv)
910 .map_err(|_| KEYERR.to_string())?
911 .apply_keystream(&mut buf);
912 Ok(buf)
913 }
914 ("aes-192-ctr", _) => {
915 let mut buf = data.to_vec();
916 ctr::Ctr128BE::<aes::Aes192>::new_from_slices(key, iv)
917 .map_err(|_| KEYERR.to_string())?
918 .apply_keystream(&mut buf);
919 Ok(buf)
920 }
921 ("aes-256-ctr", _) => {
922 let mut buf = data.to_vec();
923 ctr::Ctr128BE::<aes::Aes256>::new_from_slices(key, iv)
924 .map_err(|_| KEYERR.to_string())?
925 .apply_keystream(&mut buf);
926 Ok(buf)
927 }
928 _ => Err(format!("Error: Unsupported cipher: {algo}")),
929 }
930}
931
932fn key_len(algo: &str) -> usize {
934 if algo.starts_with("aes-128") {
935 16
936 } else if algo.starts_with("aes-192") {
937 24
938 } else {
939 32
940 }
941}
942
943fn encode_out(bytes: &[u8], enc: Option<&str>) -> Value {
945 match enc {
946 Some("hex") => with_host(|h| h.new_str(to_hex(bytes))),
947 Some("base64") | Some("base64url") => with_host(|h| h.new_str(to_base64(bytes))),
948 Some("latin1") | Some("binary") => {
949 with_host(|h| h.new_str(bytes.iter().map(|b| *b as char).collect::<String>()))
950 }
951 Some("utf8") | Some("utf-8") => {
952 with_host(|h| h.new_str(String::from_utf8_lossy(bytes).into_owned()))
953 }
954 _ => super::buffer::from_bytes(bytes),
955 }
956}
957
958fn cipher_info(algo: &str) -> Result<Value, String> {
960 if !CIPHERS.contains(&algo) {
961 return Ok(Value::Undef);
962 }
963 let nid = match algo {
964 "aes-128-cbc" => 419,
965 "aes-192-cbc" => 423,
966 "aes-256-cbc" => 427,
967 "aes-128-ctr" => 904,
968 "aes-192-ctr" => 905,
969 _ => 906,
970 };
971 let (mode, block) = if algo.ends_with("ctr") {
972 ("ctr", 1)
973 } else {
974 ("cbc", 16)
975 };
976 Ok(with_host(|h| {
977 let mut m = IndexMap::new();
978 m.insert("mode".into(), h.new_str(mode));
979 m.insert("name".into(), h.new_str(algo));
980 m.insert("nid".into(), Value::Float(nid as f64));
981 m.insert("keyLength".into(), Value::Float(key_len(algo) as f64));
982 m.insert("blockSize".into(), Value::Float(block as f64));
983 m.insert("ivLength".into(), Value::Float(16.0));
984 h.new_object(m)
985 }))
986}
987
988fn random_fill(args: &[Value]) -> Result<Value, String> {
991 let buf = args.first().cloned().unwrap_or(Value::Undef);
992 if super::native_tag(&buf).as_deref() != Some("Buffer") {
993 return Err("Error: The \"buf\" argument must be a Buffer".into());
994 }
995 let cur = val_bytes(&buf);
996 let len = cur.len();
997 let offset = if args.len() > 1 {
998 super::arg_num(args, 1).max(0.0) as usize
999 } else {
1000 0
1001 };
1002 let offset = offset.min(len);
1003 let size = if args.len() > 2 {
1004 super::arg_num(args, 2).max(0.0) as usize
1005 } else {
1006 len - offset
1007 };
1008 let end = (offset + size).min(len);
1009 let mut rnd = vec![0u8; end.saturating_sub(offset)];
1010 if let Err(e) = getrandom::getrandom(&mut rnd) {
1011 return Err(format!("Error: failed to generate random bytes: {e}"));
1012 }
1013 let mut out = cur;
1014 out[offset..end].copy_from_slice(&rnd);
1015 with_host(|h| {
1016 let arr = match h.get(&buf) {
1017 Some(JsObj::Object(p)) => p.get("@@bytes").cloned(),
1018 _ => None,
1019 };
1020 if let Some(a) = arr {
1021 if let Some(JsObj::Array(items)) = h.get_mut(&a) {
1022 *items = out.iter().map(|b| Value::Float(*b as f64)).collect();
1023 }
1024 }
1025 });
1026 Ok(buf)
1027}
1028
1029fn uuid_v7() -> Result<Value, String> {
1032 let ms = std::time::SystemTime::now()
1033 .duration_since(std::time::UNIX_EPOCH)
1034 .map(|d| d.as_millis() as u64)
1035 .unwrap_or(0);
1036 let mut b = [0u8; 16];
1037 if let Err(e) = getrandom::getrandom(&mut b) {
1038 return Err(format!("Error: failed to generate random bytes: {e}"));
1039 }
1040 b[0..6].copy_from_slice(&ms.to_be_bytes()[2..8]);
1041 b[6] = (b[6] & 0x0f) | 0x70;
1042 b[8] = (b[8] & 0x3f) | 0x80;
1043 let h = to_hex(&b);
1044 let uuid = format!(
1045 "{}-{}-{}-{}-{}",
1046 &h[0..8],
1047 &h[8..12],
1048 &h[12..16],
1049 &h[16..20],
1050 &h[20..32]
1051 );
1052 Ok(with_host(|host| host.new_str(uuid)))
1053}
1054
1055fn random_below(range: u64) -> Result<u64, getrandom::Error> {
1058 let limit = u64::MAX - (u64::MAX % range);
1060 loop {
1061 let mut b = [0u8; 8];
1062 getrandom::getrandom(&mut b)?;
1063 let n = u64::from_le_bytes(b);
1064 if n < limit {
1065 return Ok(n % range);
1066 }
1067 }
1068}
1069
1070fn decode(s: &str, enc: &str) -> Vec<u8> {
1071 match enc.to_ascii_lowercase().as_str() {
1072 "hex" => super::from_hex(s),
1073 "base64" | "base64url" => super::from_base64(s),
1074 "ascii" | "latin1" | "binary" => s.chars().map(|c| c as u8).collect(),
1075 _ => s.as_bytes().to_vec(),
1076 }
1077}
1078
1079fn key_object(kind: &str, asym: &str, pem: &str) -> Value {
1087 with_host(|h| {
1088 let mut m = IndexMap::new();
1089 m.insert("@@native".into(), h.new_str("KeyObject"));
1090 m.insert("type".into(), h.new_str(kind));
1091 m.insert("asymmetricKeyType".into(), h.new_str(asym));
1092 m.insert("@@pem".into(), h.new_str(pem));
1093 h.new_object(m)
1094 })
1095}
1096
1097fn secret_key_object(bytes: &[u8]) -> Value {
1099 with_host(|h| {
1100 let arr = h.new_array(bytes.iter().map(|b| Value::Float(*b as f64)).collect());
1101 let mut m = IndexMap::new();
1102 m.insert("@@native".into(), h.new_str("KeyObject"));
1103 m.insert("type".into(), h.new_str("secret"));
1104 m.insert("@@secret".into(), arr);
1105 h.new_object(m)
1106 })
1107}
1108
1109fn pem_wrap(label: &str, der: &[u8]) -> String {
1111 let b64 = to_base64(der);
1112 let mut s = format!("-----BEGIN {label}-----\n");
1113 for chunk in b64.as_bytes().chunks(64) {
1114 s.push_str(std::str::from_utf8(chunk).unwrap_or_default());
1115 s.push('\n');
1116 }
1117 s.push_str(&format!("-----END {label}-----\n"));
1118 s
1119}
1120
1121fn pem_body(pem: &str) -> Vec<u8> {
1123 let body: String = pem.lines().filter(|l| !l.starts_with("-----")).collect();
1124 super::from_base64(&body)
1125}
1126
1127fn x25519_private_pem(raw: &[u8]) -> String {
1129 let mut der = vec![
1130 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04,
1131 0x20,
1132 ];
1133 der.extend_from_slice(raw);
1134 pem_wrap("PRIVATE KEY", &der)
1135}
1136
1137fn x25519_public_pem(raw: &[u8]) -> String {
1139 let mut der = vec![
1140 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
1141 ];
1142 der.extend_from_slice(raw);
1143 pem_wrap("PUBLIC KEY", &der)
1144}
1145
1146fn x25519_raw(pem: &str) -> Option<[u8; 32]> {
1148 let der = pem_body(pem);
1149 if der.len() < 32 {
1150 return None;
1151 }
1152 let mut out = [0u8; 32];
1153 out.copy_from_slice(&der[der.len() - 32..]);
1154 Some(out)
1155}
1156
1157fn keygen_encoding(opts: Option<&Value>, priv_side: bool) -> Option<String> {
1159 let o = opts?;
1160 let field = if priv_side {
1161 "privateKeyEncoding"
1162 } else {
1163 "publicKeyEncoding"
1164 };
1165 with_host(|h| {
1166 let JsObj::Object(p) = h.get(o)? else {
1167 return None;
1168 };
1169 let enc = p.get(field)?;
1170 let JsObj::Object(e) = h.get(enc)? else {
1171 return None;
1172 };
1173 e.get("format").map(|v| h.str_of(v))
1174 })
1175}
1176
1177fn generate_key_pair(kind: &str, opts: Option<&Value>) -> Result<Value, String> {
1181 let mut rng = rand_core::OsRng;
1182 let (asym, priv_pem, pub_pem) = match kind {
1183 "rsa" => {
1184 let bits = opt_num(opts.unwrap_or(&Value::Undef), &["modulusLength"], 2048.0) as usize;
1185 let sk = rsa::RsaPrivateKey::new(&mut rng, bits).map_err(|e| format!("Error: {e}"))?;
1186 let pk = rsa::RsaPublicKey::from(&sk);
1187 let priv_pem = sk
1188 .to_pkcs8_pem(LineEnding::LF)
1189 .map_err(|e| format!("Error: {e}"))?
1190 .to_string();
1191 let pub_pem = pk
1192 .to_public_key_pem(LineEnding::LF)
1193 .map_err(|e| format!("Error: {e}"))?;
1194 ("rsa", priv_pem, pub_pem)
1195 }
1196 "ec" => {
1197 let curve = opt_str(opts.unwrap_or(&Value::Undef), "namedCurve");
1198 match ec_curve_id(&curve) {
1199 Some("p256") => {
1200 let sk = p256::SecretKey::random(&mut rng);
1201 let priv_pem = sk
1202 .to_pkcs8_pem(LineEnding::LF)
1203 .map_err(|e| format!("Error: {e}"))?
1204 .to_string();
1205 let pub_pem = sk
1206 .public_key()
1207 .to_public_key_pem(LineEnding::LF)
1208 .map_err(|e| format!("Error: {e}"))?;
1209 ("ec", priv_pem, pub_pem)
1210 }
1211 Some("p384") => {
1212 let sk = p384::SecretKey::random(&mut rng);
1213 let priv_pem = sk
1214 .to_pkcs8_pem(LineEnding::LF)
1215 .map_err(|e| format!("Error: {e}"))?
1216 .to_string();
1217 let pub_pem = sk
1218 .public_key()
1219 .to_public_key_pem(LineEnding::LF)
1220 .map_err(|e| format!("Error: {e}"))?;
1221 ("ec", priv_pem, pub_pem)
1222 }
1223 _ => return Err(format!("Error: Unsupported EC curve: {curve}")),
1224 }
1225 }
1226 "ed25519" => {
1227 let sk = ed25519_dalek::SigningKey::generate(&mut rng);
1228 let priv_pem = sk
1229 .to_pkcs8_pem(LineEnding::LF)
1230 .map_err(|e| format!("Error: {e}"))?
1231 .to_string();
1232 let pub_pem = sk
1233 .verifying_key()
1234 .to_public_key_pem(LineEnding::LF)
1235 .map_err(|e| format!("Error: {e}"))?;
1236 ("ed25519", priv_pem, pub_pem)
1237 }
1238 "x25519" => {
1239 let sk = x25519_dalek::StaticSecret::random_from_rng(rng);
1240 let pk = x25519_dalek::PublicKey::from(&sk);
1241 (
1242 "x25519",
1243 x25519_private_pem(&sk.to_bytes()),
1244 x25519_public_pem(pk.as_bytes()),
1245 )
1246 }
1247 _ => return Err(format!("Error: Unsupported key type: {kind}")),
1248 };
1249 let pub_is_pem = keygen_encoding(opts, false).as_deref() == Some("pem");
1250 let priv_is_pem = keygen_encoding(opts, true).as_deref() == Some("pem");
1251 let publik = if pub_is_pem {
1252 with_host(|h| h.new_str(pub_pem.clone()))
1253 } else {
1254 key_object("public", asym, &pub_pem)
1255 };
1256 let privat = if priv_is_pem {
1257 with_host(|h| h.new_str(priv_pem.clone()))
1258 } else {
1259 key_object("private", asym, &priv_pem)
1260 };
1261 Ok(with_host(|h| {
1262 let mut m = IndexMap::new();
1263 m.insert("publicKey".into(), publik);
1264 m.insert("privateKey".into(), privat);
1265 h.new_object(m)
1266 }))
1267}
1268
1269fn ec_curve_id(name: &str) -> Option<&'static str> {
1271 match name {
1272 "P-256" | "prime256v1" | "secp256r1" => Some("p256"),
1273 "P-384" | "secp384r1" => Some("p384"),
1274 _ => None,
1275 }
1276}
1277
1278fn opt_str(obj: &Value, key: &str) -> String {
1280 with_host(|h| match h.get(obj) {
1281 Some(JsObj::Object(p)) => p.get(key).map(|v| h.str_of(v)).unwrap_or_default(),
1282 _ => String::new(),
1283 })
1284}
1285
1286fn detect_private(bytes: &[u8]) -> Option<&'static str> {
1288 let pem = std::str::from_utf8(bytes).ok();
1289 if pem
1290 .map(|p| {
1291 rsa::RsaPrivateKey::from_pkcs8_pem(p).is_ok()
1292 || rsa::RsaPrivateKey::from_pkcs1_pem(p).is_ok()
1293 })
1294 .unwrap_or(false)
1295 || rsa::RsaPrivateKey::from_pkcs8_der(bytes).is_ok()
1296 {
1297 return Some("rsa");
1298 }
1299 if pem
1300 .map(|p| p256::SecretKey::from_pkcs8_pem(p).is_ok())
1301 .unwrap_or(false)
1302 {
1303 return Some("ec");
1304 }
1305 if pem
1306 .map(|p| p384::SecretKey::from_pkcs8_pem(p).is_ok())
1307 .unwrap_or(false)
1308 {
1309 return Some("ec");
1310 }
1311 if pem
1312 .map(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).is_ok())
1313 .unwrap_or(false)
1314 {
1315 return Some("ed25519");
1316 }
1317 if pem.map(|p| p.contains("PRIVATE KEY")).unwrap_or(false)
1318 && x25519_raw(pem.unwrap_or("")).is_some()
1319 {
1320 let der = pem_body(pem.unwrap_or(""));
1322 if der.len() == 48 && der[9..12] == [0x2b, 0x65, 0x6e] {
1323 return Some("x25519");
1324 }
1325 }
1326 None
1327}
1328
1329fn detect_public(bytes: &[u8]) -> Option<&'static str> {
1331 let pem = std::str::from_utf8(bytes).ok();
1332 if pem
1333 .map(|p| rsa::RsaPublicKey::from_public_key_pem(p).is_ok())
1334 .unwrap_or(false)
1335 {
1336 return Some("rsa");
1337 }
1338 if pem
1339 .map(|p| p256::PublicKey::from_public_key_pem(p).is_ok())
1340 .unwrap_or(false)
1341 {
1342 return Some("ec");
1343 }
1344 if pem
1345 .map(|p| p384::PublicKey::from_public_key_pem(p).is_ok())
1346 .unwrap_or(false)
1347 {
1348 return Some("ec");
1349 }
1350 if pem
1351 .map(|p| ed25519_dalek::VerifyingKey::from_public_key_pem(p).is_ok())
1352 .unwrap_or(false)
1353 {
1354 return Some("ed25519");
1355 }
1356 if let Some(p) = pem {
1357 let der = pem_body(p);
1358 if der.len() == 44 && der[6..9] == [0x2b, 0x65, 0x6e] {
1359 return Some("x25519");
1360 }
1361 }
1362 None
1363}
1364
1365fn create_private_key(input: Option<&Value>) -> Result<Value, String> {
1367 let bytes = input.map(key_material).unwrap_or_default();
1368 let asym = detect_private(&bytes).ok_or("Error: Failed to read private key")?;
1369 let pem = String::from_utf8_lossy(&bytes).into_owned();
1370 Ok(key_object("private", asym, &pem))
1371}
1372
1373fn create_public_key(input: Option<&Value>) -> Result<Value, String> {
1376 let bytes = input.map(key_material).unwrap_or_default();
1377 if let Some(asym) = detect_public(&bytes) {
1378 let pem = String::from_utf8_lossy(&bytes).into_owned();
1379 return Ok(key_object("public", asym, &pem));
1380 }
1381 if let Some(asym) = detect_private(&bytes) {
1383 let pem = public_pem_from_private(&bytes, asym)?;
1384 return Ok(key_object("public", asym, &pem));
1385 }
1386 Err("Error: Failed to read public key".into())
1387}
1388
1389fn public_pem_from_private(bytes: &[u8], asym: &str) -> Result<String, String> {
1391 let pem = std::str::from_utf8(bytes).ok();
1392 let err = || "Error: Failed to derive public key".to_string();
1393 match asym {
1394 "rsa" => {
1395 let sk = pem
1396 .and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1397 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(bytes).ok())
1398 .ok_or_else(err)?;
1399 rsa::RsaPublicKey::from(&sk)
1400 .to_public_key_pem(LineEnding::LF)
1401 .map_err(|e| format!("Error: {e}"))
1402 }
1403 "ec" => {
1404 if let Some(sk) = pem.and_then(|p| p256::SecretKey::from_pkcs8_pem(p).ok()) {
1405 return sk
1406 .public_key()
1407 .to_public_key_pem(LineEnding::LF)
1408 .map_err(|e| format!("Error: {e}"));
1409 }
1410 let sk = pem
1411 .and_then(|p| p384::SecretKey::from_pkcs8_pem(p).ok())
1412 .ok_or_else(err)?;
1413 sk.public_key()
1414 .to_public_key_pem(LineEnding::LF)
1415 .map_err(|e| format!("Error: {e}"))
1416 }
1417 "ed25519" => {
1418 let sk = pem
1419 .and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok())
1420 .ok_or_else(err)?;
1421 sk.verifying_key()
1422 .to_public_key_pem(LineEnding::LF)
1423 .map_err(|e| format!("Error: {e}"))
1424 }
1425 "x25519" => {
1426 let raw = pem.and_then(x25519_raw).ok_or_else(err)?;
1427 let sk = x25519_dalek::StaticSecret::from(raw);
1428 Ok(x25519_public_pem(
1429 x25519_dalek::PublicKey::from(&sk).as_bytes(),
1430 ))
1431 }
1432 _ => Err(err()),
1433 }
1434}
1435
1436fn key_material(v: &Value) -> Vec<u8> {
1439 if super::native_tag(v).as_deref() == Some("KeyObject") {
1440 return with_host(|h| match h.get(v) {
1441 Some(JsObj::Object(p)) => p.get("@@pem").map(|s| h.str_of(s)).unwrap_or_default(),
1442 _ => String::new(),
1443 })
1444 .into_bytes();
1445 }
1446 if super::native_tag(v).as_deref() != Some("Buffer") {
1447 let inner = with_host(|h| match h.get(v) {
1448 Some(JsObj::Object(p)) => p.get("key").cloned(),
1449 _ => None,
1450 });
1451 if let Some(k) = inner {
1452 return key_material(&k);
1453 }
1454 }
1455 val_bytes(v)
1456}
1457
1458fn new_sign_verify(tag: &str, algo: &str) -> Value {
1461 with_host(|h| {
1462 let data = h.new_array(Vec::new());
1463 let mut m = IndexMap::new();
1464 m.insert("@@native".into(), h.new_str(tag));
1465 m.insert("@@algo".into(), h.new_str(algo.to_ascii_lowercase()));
1466 m.insert("@@data".into(), data);
1467 h.new_object(m)
1468 })
1469}
1470
1471fn digest_of(algo: &str) -> String {
1473 let a = algo.to_ascii_lowercase();
1474 let a = a.strip_prefix("rsa-").unwrap_or(&a);
1475 a.replace('-', "")
1476}
1477
1478fn sign_data(key: &[u8], algo: &str, data: &[u8]) -> Result<Vec<u8>, String> {
1480 let pem = std::str::from_utf8(key).ok();
1481 let d = digest_of(algo);
1482 if let Some(sk) = pem
1483 .and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1484 .or_else(|| pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs1_pem(p).ok()))
1485 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(key).ok())
1486 {
1487 return rsa_sign(&sk, &d, data);
1488 }
1489 if let Some(sk) = pem.and_then(|p| p256::ecdsa::SigningKey::from_pkcs8_pem(p).ok()) {
1490 let sig: p256::ecdsa::Signature = sk.try_sign(data).map_err(|e| format!("Error: {e}"))?;
1491 return Ok(sig.to_der().as_bytes().to_vec());
1492 }
1493 if let Some(sk) = pem.and_then(|p| p384::ecdsa::SigningKey::from_pkcs8_pem(p).ok()) {
1494 let sig: p384::ecdsa::Signature = sk.try_sign(data).map_err(|e| format!("Error: {e}"))?;
1495 return Ok(sig.to_der().as_bytes().to_vec());
1496 }
1497 if let Some(sk) = pem.and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok()) {
1498 return Ok(sk.sign(data).to_bytes().to_vec());
1499 }
1500 Err("Error: Invalid or unsupported private key for signing".into())
1501}
1502
1503fn rsa_sign(sk: &rsa::RsaPrivateKey, digest: &str, data: &[u8]) -> Result<Vec<u8>, String> {
1505 let sig = match digest {
1506 "sha256" => rsa::pkcs1v15::SigningKey::<Sha256>::new(sk.clone())
1507 .sign(data)
1508 .to_vec(),
1509 "sha384" => rsa::pkcs1v15::SigningKey::<Sha384>::new(sk.clone())
1510 .sign(data)
1511 .to_vec(),
1512 "sha512" => rsa::pkcs1v15::SigningKey::<Sha512>::new(sk.clone())
1513 .sign(data)
1514 .to_vec(),
1515 _ => {
1516 return Err(format!(
1517 "Error: Unsupported digest for RSA signing: {digest}"
1518 ))
1519 }
1520 };
1521 Ok(sig)
1522}
1523
1524fn verify_data(key: &[u8], algo: &str, data: &[u8], sig: &[u8]) -> Result<bool, String> {
1526 let pem = std::str::from_utf8(key).ok();
1527 let d = digest_of(algo);
1528 if let Some(pk) = pem
1529 .and_then(|p| rsa::RsaPublicKey::from_public_key_pem(p).ok())
1530 .or_else(|| pem.and_then(|p| rsa::RsaPublicKey::from_pkcs1_pem(p).ok()))
1531 .or_else(|| {
1532 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1533 .map(|s| rsa::RsaPublicKey::from(&s))
1534 })
1535 {
1536 return rsa_verify(&pk, &d, data, sig);
1537 }
1538 if let Some(vk) = pem
1539 .and_then(|p| p256::ecdsa::VerifyingKey::from_public_key_pem(p).ok())
1540 .or_else(|| {
1541 pem.and_then(|p| p256::ecdsa::SigningKey::from_pkcs8_pem(p).ok())
1542 .map(|s| *s.verifying_key())
1543 })
1544 {
1545 let s = p256::ecdsa::Signature::from_der(sig).map_err(|e| format!("Error: {e}"))?;
1546 return Ok(vk.verify(data, &s).is_ok());
1547 }
1548 if let Some(vk) = pem
1549 .and_then(|p| p384::ecdsa::VerifyingKey::from_public_key_pem(p).ok())
1550 .or_else(|| {
1551 pem.and_then(|p| p384::ecdsa::SigningKey::from_pkcs8_pem(p).ok())
1552 .map(|s| *s.verifying_key())
1553 })
1554 {
1555 let s = p384::ecdsa::Signature::from_der(sig).map_err(|e| format!("Error: {e}"))?;
1556 return Ok(vk.verify(data, &s).is_ok());
1557 }
1558 if let Some(vk) = pem
1559 .and_then(|p| ed25519_dalek::VerifyingKey::from_public_key_pem(p).ok())
1560 .or_else(|| {
1561 pem.and_then(|p| ed25519_dalek::SigningKey::from_pkcs8_pem(p).ok())
1562 .map(|s| s.verifying_key())
1563 })
1564 {
1565 let s = ed25519_dalek::Signature::from_slice(sig).map_err(|e| format!("Error: {e}"))?;
1566 return Ok(vk.verify(data, &s).is_ok());
1567 }
1568 Err("Error: Invalid or unsupported public key for verifying".into())
1569}
1570
1571fn rsa_verify(
1573 pk: &rsa::RsaPublicKey,
1574 digest: &str,
1575 data: &[u8],
1576 sig: &[u8],
1577) -> Result<bool, String> {
1578 let signature = match rsa::pkcs1v15::Signature::try_from(sig) {
1579 Ok(s) => s,
1580 Err(_) => return Ok(false),
1581 };
1582 let ok = match digest {
1583 "sha256" => rsa::pkcs1v15::VerifyingKey::<Sha256>::new(pk.clone())
1584 .verify(data, &signature)
1585 .is_ok(),
1586 "sha384" => rsa::pkcs1v15::VerifyingKey::<Sha384>::new(pk.clone())
1587 .verify(data, &signature)
1588 .is_ok(),
1589 "sha512" => rsa::pkcs1v15::VerifyingKey::<Sha512>::new(pk.clone())
1590 .verify(data, &signature)
1591 .is_ok(),
1592 _ => {
1593 return Err(format!(
1594 "Error: Unsupported digest for RSA verifying: {digest}"
1595 ))
1596 }
1597 };
1598 Ok(ok)
1599}
1600
1601pub fn sign_verify_instance_call(
1603 tag: &str,
1604 recv: &Value,
1605 method: &str,
1606 args: &[Value],
1607) -> Result<Value, String> {
1608 match method {
1609 "update" => {
1610 let enc = if args.len() > 1 {
1611 arg_str(args, 1)
1612 } else {
1613 "utf8".into()
1614 };
1615 let bytes = if super::native_tag(args.first().unwrap_or(&Value::Undef)).as_deref()
1616 == Some("Buffer")
1617 {
1618 val_bytes_at(args, 0)
1619 } else {
1620 decode(&arg_str(args, 0), &enc)
1621 };
1622 with_host(|h| {
1623 if let Some(JsObj::Object(p)) = h.get(recv).cloned() {
1624 if let Some(arr) = p.get("@@data").cloned() {
1625 if let Some(JsObj::Array(items)) = h.get_mut(&arr) {
1626 items.extend(bytes.iter().map(|b| Value::Float(*b as f64)));
1627 }
1628 }
1629 }
1630 });
1631 Ok(recv.clone())
1632 }
1633 "sign" => {
1634 let (algo, data) = sign_verify_state(recv);
1635 let key = key_material(args.first().unwrap_or(&Value::Undef));
1636 let sig = sign_data(&key, &algo, &data)?;
1637 let out_enc = if args.len() > 1 {
1638 Some(arg_str(args, 1))
1639 } else {
1640 None
1641 };
1642 Ok(encode_out(&sig, out_enc.as_deref()))
1643 }
1644 "verify" => {
1645 let (algo, data) = sign_verify_state(recv);
1646 let key = key_material(args.first().unwrap_or(&Value::Undef));
1647 let sig = if args.len() > 2 {
1648 decode(&arg_str(args, 1), &arg_str(args, 2))
1649 } else {
1650 val_bytes_at(args, 1)
1651 };
1652 Ok(Value::Bool(verify_data(&key, &algo, &data, &sig)?))
1653 }
1654 _ => Err(crate::host::type_error(&format!(
1655 "{}.{method} is not a function",
1656 tag.to_ascii_lowercase()
1657 ))),
1658 }
1659}
1660
1661fn sign_verify_state(recv: &Value) -> (String, Vec<u8>) {
1663 with_host(|h| {
1664 let (mut algo, mut data) = (String::new(), Vec::new());
1665 if let Some(JsObj::Object(p)) = h.get(recv) {
1666 algo = p.get("@@algo").map(|v| h.str_of(v)).unwrap_or_default();
1667 if let Some(JsObj::Array(items)) = p.get("@@data").and_then(|v| h.get(v)) {
1668 data = items.iter().map(|v| h.to_number(v) as u8).collect();
1669 }
1670 }
1671 (algo, data)
1672 })
1673}
1674
1675fn rsa_padding(v: &Value) -> (i64, String) {
1677 let padding = opt_num(v, &["padding"], 4.0) as i64; let oaep = {
1679 let h = opt_str(v, "oaepHash");
1680 if h.is_empty() {
1681 "sha1".to_string()
1682 } else {
1683 h.to_ascii_lowercase()
1684 }
1685 };
1686 (padding, oaep)
1687}
1688
1689fn parse_rsa_public(key: &[u8]) -> Result<rsa::RsaPublicKey, String> {
1691 let pem = std::str::from_utf8(key).ok();
1692 pem.and_then(|p| rsa::RsaPublicKey::from_public_key_pem(p).ok())
1693 .or_else(|| pem.and_then(|p| rsa::RsaPublicKey::from_pkcs1_pem(p).ok()))
1694 .or_else(|| rsa::RsaPublicKey::from_public_key_der(key).ok())
1695 .or_else(|| {
1696 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1697 .map(|s| rsa::RsaPublicKey::from(&s))
1698 })
1699 .ok_or_else(|| "Error: Failed to parse RSA public key".into())
1700}
1701
1702fn parse_rsa_private(key: &[u8]) -> Result<rsa::RsaPrivateKey, String> {
1704 let pem = std::str::from_utf8(key).ok();
1705 pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs8_pem(p).ok())
1706 .or_else(|| pem.and_then(|p| rsa::RsaPrivateKey::from_pkcs1_pem(p).ok()))
1707 .or_else(|| rsa::RsaPrivateKey::from_pkcs8_der(key).ok())
1708 .ok_or_else(|| "Error: Failed to parse RSA private key".into())
1709}
1710
1711fn rsa_public_op(args: &[Value], _public: bool, encrypt: bool) -> Result<Value, String> {
1714 let key_arg = args.first().cloned().unwrap_or(Value::Undef);
1715 let key = key_material(&key_arg);
1716 let (padding, oaep) = rsa_padding(&key_arg);
1717 let data = val_bytes_at(args, 1);
1718 let out = if encrypt {
1719 let pk = parse_rsa_public(&key)?;
1720 let mut rng = rand_core::OsRng;
1721 if padding == 1 {
1722 pk.encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &data)
1723 } else if oaep == "sha256" {
1724 pk.encrypt(&mut rng, rsa::Oaep::new::<Sha256>(), &data)
1725 } else {
1726 pk.encrypt(&mut rng, rsa::Oaep::new::<Sha1>(), &data)
1727 }
1728 .map_err(|e| format!("Error: {e}"))?
1729 } else {
1730 let sk = parse_rsa_private(&key)?;
1731 if padding == 1 {
1732 sk.decrypt(rsa::Pkcs1v15Encrypt, &data)
1733 } else if oaep == "sha256" {
1734 sk.decrypt(rsa::Oaep::new::<Sha256>(), &data)
1735 } else {
1736 sk.decrypt(rsa::Oaep::new::<Sha1>(), &data)
1737 }
1738 .map_err(|e| format!("Error: {e}"))?
1739 };
1740 Ok(super::buffer::from_bytes(&out))
1741}
1742
1743fn rsa_private_encrypt(args: &[Value]) -> Result<Value, String> {
1746 let key = key_material(args.first().unwrap_or(&Value::Undef));
1747 let data = val_bytes_at(args, 1);
1748 let sk = parse_rsa_private(&key)?;
1749 let out = sk
1750 .sign(rsa::Pkcs1v15Sign::new_unprefixed(), &data)
1751 .map_err(|e| format!("Error: {e}"))?;
1752 Ok(super::buffer::from_bytes(&out))
1753}
1754
1755fn rsa_public_decrypt(args: &[Value]) -> Result<Value, String> {
1758 use rsa::traits::PublicKeyParts;
1759 let key = key_material(args.first().unwrap_or(&Value::Undef));
1760 let ct = val_bytes_at(args, 1);
1761 let pk = parse_rsa_public(&key)?;
1762 let n = BigUint::from_bytes_be(&pk.n().to_bytes_be());
1763 let e = BigUint::from_bytes_be(&pk.e().to_bytes_be());
1764 let k = pk.n().to_bytes_be().len();
1765 let s = BigUint::from_bytes_be(&ct);
1766 let m = s.modpow(&e, &n);
1767 let mut em = m.to_bytes_be();
1768 while em.len() < k {
1769 em.insert(0, 0);
1770 }
1771 if em.len() < 11 || em[0] != 0x00 || em[1] != 0x01 {
1773 return Err("Error: error:0200006E:rsa routines::padding check failed".into());
1774 }
1775 let sep = em[2..].iter().position(|&b| b == 0x00).map(|i| i + 2);
1776 match sep {
1777 Some(i) => Ok(super::buffer::from_bytes(&em[i + 1..])),
1778 None => Err("Error: error:0200006E:rsa routines::padding check failed".into()),
1779 }
1780}
1781
1782const MODP_GROUPS: &[(&str, &str)] = &[
1786 ("modp1", MODP1),
1787 ("modp2", MODP2),
1788 ("modp5", MODP5),
1789 ("modp14", MODP14),
1790 ("modp15", MODP15),
1791 ("modp16", MODP16),
1792 ("modp17", MODP17),
1793 ("modp18", MODP18),
1794];
1795
1796fn obj_bytes(recv: &Value, key: &str) -> Vec<u8> {
1798 with_host(|h| {
1799 if let Some(JsObj::Object(p)) = h.get(recv) {
1800 if let Some(JsObj::Array(it)) = p.get(key).and_then(|v| h.get(v)) {
1801 return it.iter().map(|v| h.to_number(v) as u8).collect();
1802 }
1803 }
1804 Vec::new()
1805 })
1806}
1807
1808fn set_obj_bytes(recv: &Value, key: &str, bytes: &[u8]) {
1810 with_host(|h| {
1811 let arr = h.new_array(bytes.iter().map(|b| Value::Float(*b as f64)).collect());
1812 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
1813 p.insert(key.to_string(), arr);
1814 }
1815 });
1816}
1817
1818fn dh_object(prime: &[u8], gen: &[u8]) -> Value {
1820 with_host(|h| {
1821 let pv = h.new_array(prime.iter().map(|b| Value::Float(*b as f64)).collect());
1822 let gv = h.new_array(gen.iter().map(|b| Value::Float(*b as f64)).collect());
1823 let mut m = IndexMap::new();
1824 m.insert("@@native".into(), h.new_str("DiffieHellman"));
1825 m.insert("@@prime".into(), pv);
1826 m.insert("@@gen".into(), gv);
1827 h.new_object(m)
1828 })
1829}
1830
1831fn create_diffie_hellman(args: &[Value]) -> Result<Value, String> {
1833 let first = args.first().cloned().unwrap_or(Value::Undef);
1835 if matches!(first, Value::Int(_) | Value::Float(_)) {
1836 let bits = super::arg_num(args, 0) as usize;
1837 let prime = gen_prime(bits)?;
1838 return Ok(dh_object(&prime.to_bytes_be(), &[2]));
1839 }
1840 let prime = val_bytes_at(args, 0);
1841 let gen = if args.len() > 1 {
1842 match args.get(1) {
1843 Some(Value::Int(_)) | Some(Value::Float(_)) => {
1844 let g = super::arg_num(args, 1) as u64;
1845 BigUint::from(g).to_bytes_be()
1846 }
1847 _ => val_bytes_at(args, 1),
1848 }
1849 } else {
1850 vec![2]
1851 };
1852 Ok(dh_object(&prime, &gen))
1853}
1854
1855fn diffie_hellman_group(name: &str) -> Result<Value, String> {
1857 let hex = MODP_GROUPS
1858 .iter()
1859 .find(|(n, _)| *n == name)
1860 .map(|(_, h)| *h)
1861 .ok_or_else(|| format!("Error: Unknown group: {name}"))?;
1862 Ok(dh_object(&super::from_hex(hex), &[2]))
1863}
1864
1865pub fn dh_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
1867 let enc = |args: &[Value], i: usize| -> Option<String> {
1868 if args.len() > i {
1869 let s = arg_str(args, i);
1870 if s.is_empty() {
1871 None
1872 } else {
1873 Some(s)
1874 }
1875 } else {
1876 None
1877 }
1878 };
1879 match method {
1880 "generateKeys" => {
1881 let p = BigUint::from_bytes_be(&obj_bytes(recv, "@@prime"));
1882 let g = BigUint::from_bytes_be(&obj_bytes(recv, "@@gen"));
1883 let priv_key = dh_random_priv(&p)?;
1884 let pub_key = g.modpow(&priv_key, &p);
1885 set_obj_bytes(recv, "@@priv", &priv_key.to_bytes_be());
1886 set_obj_bytes(recv, "@@pub", &pub_key.to_bytes_be());
1887 Ok(encode_out(&pub_key.to_bytes_be(), enc(args, 0).as_deref()))
1888 }
1889 "computeSecret" => {
1890 let other = if args.len() > 1
1891 && !arg_str(args, 1).is_empty()
1892 && !matches!(args.first(), Some(v) if super::native_tag(v).as_deref() == Some("Buffer"))
1893 {
1894 decode(&arg_str(args, 0), &arg_str(args, 1))
1895 } else {
1896 val_bytes_at(args, 0)
1897 };
1898 let p = BigUint::from_bytes_be(&obj_bytes(recv, "@@prime"));
1899 let priv_key = BigUint::from_bytes_be(&obj_bytes(recv, "@@priv"));
1900 let their_pub = BigUint::from_bytes_be(&other);
1901 let secret = their_pub.modpow(&priv_key, &p);
1902 let out_enc = if args.len() > 2 { enc(args, 2) } else { None };
1903 Ok(encode_out(&secret.to_bytes_be(), out_enc.as_deref()))
1904 }
1905 "getPrime" => Ok(encode_out(
1906 &obj_bytes(recv, "@@prime"),
1907 enc(args, 0).as_deref(),
1908 )),
1909 "getGenerator" => Ok(encode_out(
1910 &obj_bytes(recv, "@@gen"),
1911 enc(args, 0).as_deref(),
1912 )),
1913 "getPublicKey" => Ok(encode_out(
1914 &obj_bytes(recv, "@@pub"),
1915 enc(args, 0).as_deref(),
1916 )),
1917 "getPrivateKey" => Ok(encode_out(
1918 &obj_bytes(recv, "@@priv"),
1919 enc(args, 0).as_deref(),
1920 )),
1921 "setPublicKey" => {
1922 set_obj_bytes(recv, "@@pub", &val_bytes_at(args, 0));
1923 Ok(recv.clone())
1924 }
1925 "setPrivateKey" => {
1926 set_obj_bytes(recv, "@@priv", &val_bytes_at(args, 0));
1927 Ok(recv.clone())
1928 }
1929 _ => Err(crate::host::type_error(&format!(
1930 "dh.{method} is not a function"
1931 ))),
1932 }
1933}
1934
1935fn dh_random_priv(p: &BigUint) -> Result<BigUint, String> {
1937 let nbytes = p.to_bytes_be().len();
1938 let mut buf = vec![0u8; nbytes];
1939 getrandom::getrandom(&mut buf).map_err(|e| format!("Error: {e}"))?;
1940 let two = BigUint::from(2u32);
1941 let modulus = p - &two; let x = BigUint::from_bytes_be(&buf) % &modulus;
1943 Ok(x + &two)
1944}
1945
1946fn create_ecdh(curve: &str) -> Result<Value, String> {
1950 let id = ec_curve_id(curve).ok_or_else(|| format!("Error: Unsupported curve: {curve}"))?;
1951 Ok(with_host(|h| {
1952 let mut m = IndexMap::new();
1953 m.insert("@@native".into(), h.new_str("ECDH"));
1954 m.insert("@@curve".into(), h.new_str(id));
1955 h.new_object(m)
1956 }))
1957}
1958
1959pub fn ecdh_instance_call(recv: &Value, method: &str, args: &[Value]) -> Result<Value, String> {
1961 let curve = obj_str(recv, "@@curve");
1962 match method {
1963 "generateKeys" => {
1964 let (priv_b, pub_b) = ecdh_generate(&curve)?;
1965 set_obj_bytes(recv, "@@priv", &priv_b);
1966 set_obj_bytes(recv, "@@pub", &pub_b);
1967 let out_enc = if args.len() > 1 {
1968 Some(arg_str(args, 1))
1969 } else {
1970 None
1971 };
1972 Ok(encode_out(&pub_b, out_enc.as_deref()))
1973 }
1974 "computeSecret" => {
1975 let other = if args.len() > 1
1976 && !arg_str(args, 1).is_empty()
1977 && super::native_tag(args.first().unwrap_or(&Value::Undef)).as_deref()
1978 != Some("Buffer")
1979 {
1980 decode(&arg_str(args, 0), &arg_str(args, 1))
1981 } else {
1982 val_bytes_at(args, 0)
1983 };
1984 let secret = ecdh_compute(&curve, &obj_bytes(recv, "@@priv"), &other)?;
1985 let out_enc = if args.len() > 2 {
1986 Some(arg_str(args, 2))
1987 } else {
1988 None
1989 };
1990 Ok(encode_out(&secret, out_enc.as_deref()))
1991 }
1992 "getPublicKey" => {
1993 let out_enc = if args.len() > 1 {
1994 Some(arg_str(args, 1))
1995 } else {
1996 None
1997 };
1998 Ok(encode_out(&obj_bytes(recv, "@@pub"), out_enc.as_deref()))
1999 }
2000 "getPrivateKey" => {
2001 let out_enc = if !args.is_empty() {
2002 Some(arg_str(args, 0))
2003 } else {
2004 None
2005 };
2006 Ok(encode_out(&obj_bytes(recv, "@@priv"), out_enc.as_deref()))
2007 }
2008 "setPrivateKey" => {
2009 let priv_b = val_bytes_at(args, 0);
2010 let pub_b = ecdh_public_from_private(&curve, &priv_b)?;
2011 set_obj_bytes(recv, "@@priv", &priv_b);
2012 set_obj_bytes(recv, "@@pub", &pub_b);
2013 Ok(recv.clone())
2014 }
2015 _ => Err(crate::host::type_error(&format!(
2016 "ecdh.{method} is not a function"
2017 ))),
2018 }
2019}
2020
2021fn ecdh_generate(curve: &str) -> Result<(Vec<u8>, Vec<u8>), String> {
2023 let mut rng = rand_core::OsRng;
2024 match curve {
2025 "p256" => {
2026 let sk = p256::SecretKey::random(&mut rng);
2027 let pubk = sk.public_key().to_encoded_point(false).as_bytes().to_vec();
2028 Ok((sk.to_bytes().to_vec(), pubk))
2029 }
2030 "p384" => {
2031 let sk = p384::SecretKey::random(&mut rng);
2032 let pubk = sk.public_key().to_encoded_point(false).as_bytes().to_vec();
2033 Ok((sk.to_bytes().to_vec(), pubk))
2034 }
2035 _ => Err(format!("Error: Unsupported curve: {curve}")),
2036 }
2037}
2038
2039fn ecdh_public_from_private(curve: &str, priv_b: &[u8]) -> Result<Vec<u8>, String> {
2041 match curve {
2042 "p256" => {
2043 let sk = p256::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2044 Ok(sk.public_key().to_encoded_point(false).as_bytes().to_vec())
2045 }
2046 "p384" => {
2047 let sk = p384::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2048 Ok(sk.public_key().to_encoded_point(false).as_bytes().to_vec())
2049 }
2050 _ => Err(format!("Error: Unsupported curve: {curve}")),
2051 }
2052}
2053
2054fn ecdh_compute(curve: &str, priv_b: &[u8], pub_b: &[u8]) -> Result<Vec<u8>, String> {
2056 match curve {
2057 "p256" => {
2058 let sk = p256::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2059 let pk = p256::PublicKey::from_sec1_bytes(pub_b).map_err(|e| format!("Error: {e}"))?;
2060 let shared = p256::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine());
2061 Ok(shared.raw_secret_bytes().to_vec())
2062 }
2063 "p384" => {
2064 let sk = p384::SecretKey::from_slice(priv_b).map_err(|e| format!("Error: {e}"))?;
2065 let pk = p384::PublicKey::from_sec1_bytes(pub_b).map_err(|e| format!("Error: {e}"))?;
2066 let shared = p384::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine());
2067 Ok(shared.raw_secret_bytes().to_vec())
2068 }
2069 _ => Err(format!("Error: Unsupported curve: {curve}")),
2070 }
2071}
2072
2073fn obj_str(recv: &Value, key: &str) -> String {
2075 with_host(|h| match h.get(recv) {
2076 Some(JsObj::Object(p)) => p.get(key).map(|v| h.str_of(v)).unwrap_or_default(),
2077 _ => String::new(),
2078 })
2079}
2080
2081fn diffie_hellman_oneshot(opts: Option<&Value>) -> Result<Value, String> {
2083 let o = opts.ok_or("Error: options object required")?;
2084 let priv_v = with_host(|h| match h.get(o) {
2085 Some(JsObj::Object(p)) => p.get("privateKey").cloned(),
2086 _ => None,
2087 })
2088 .ok_or("Error: privateKey required")?;
2089 let pub_v = with_host(|h| match h.get(o) {
2090 Some(JsObj::Object(p)) => p.get("publicKey").cloned(),
2091 _ => None,
2092 })
2093 .ok_or("Error: publicKey required")?;
2094 let priv_bytes = key_material(&priv_v);
2095 let pub_bytes = key_material(&pub_v);
2096 let asym = detect_private(&priv_bytes).ok_or("Error: unsupported private key")?;
2097 let priv_pem = std::str::from_utf8(&priv_bytes).ok();
2098 let pub_pem = std::str::from_utf8(&pub_bytes).ok();
2099 let secret = match asym {
2100 "ec" => {
2101 if let Some(sk) = priv_pem.and_then(|p| p256::SecretKey::from_pkcs8_pem(p).ok()) {
2102 let pk = pub_pem
2103 .and_then(|p| p256::PublicKey::from_public_key_pem(p).ok())
2104 .ok_or("Error: bad public key")?;
2105 p256::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
2106 .raw_secret_bytes()
2107 .to_vec()
2108 } else {
2109 let sk = priv_pem
2110 .and_then(|p| p384::SecretKey::from_pkcs8_pem(p).ok())
2111 .ok_or("Error: bad private key")?;
2112 let pk = pub_pem
2113 .and_then(|p| p384::PublicKey::from_public_key_pem(p).ok())
2114 .ok_or("Error: bad public key")?;
2115 p384::ecdh::diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
2116 .raw_secret_bytes()
2117 .to_vec()
2118 }
2119 }
2120 "x25519" => {
2121 let sraw = priv_pem
2122 .and_then(x25519_raw)
2123 .ok_or("Error: bad private key")?;
2124 let praw = pub_pem
2125 .and_then(x25519_raw)
2126 .ok_or("Error: bad public key")?;
2127 let sk = x25519_dalek::StaticSecret::from(sraw);
2128 let pk = x25519_dalek::PublicKey::from(praw);
2129 sk.diffie_hellman(&pk).as_bytes().to_vec()
2130 }
2131 _ => return Err("Error: diffieHellman requires EC or X25519 keys".into()),
2132 };
2133 Ok(super::buffer::from_bytes(&secret))
2134}
2135
2136fn arg_biguint(v: Option<&Value>) -> BigUint {
2140 let Some(v) = v else {
2141 return BigUint::from(0u32);
2142 };
2143 if let Some(b) = with_host(|h| match h.get(v) {
2144 Some(JsObj::BigInt(b)) => b.to_biguint(),
2145 _ => None,
2146 }) {
2147 return b;
2148 }
2149 if super::native_tag(v).as_deref() == Some("Buffer") {
2150 return BigUint::from_bytes_be(&val_bytes(v));
2151 }
2152 let n = with_host(|h| h.to_number(v));
2153 BigUint::from(n.max(0.0) as u64)
2154}
2155
2156fn check_prime(v: Option<&Value>) -> bool {
2158 let n = arg_biguint(v);
2159 num_prime::nt_funcs::is_prime(&n, None).probably()
2160}
2161
2162fn generate_prime(bits: usize, opts: Option<Value>) -> Result<Value, String> {
2164 let p = gen_prime(bits)?;
2165 let want_bigint = opts
2166 .map(|o| with_host(|h| matches!(h.get(&o), Some(JsObj::Object(m)) if m.get("bigint").map(|v| h.truthy(v)).unwrap_or(false))))
2167 .unwrap_or(false);
2168 if want_bigint {
2169 Ok(with_host(|h| {
2170 h.alloc(JsObj::BigInt(num_bigint::BigInt::from(p)))
2171 }))
2172 } else {
2173 Ok(super::buffer::from_bytes(&p.to_bytes_be()))
2176 }
2177}
2178
2179fn gen_prime(bits: usize) -> Result<BigUint, String> {
2181 if bits < 2 {
2182 return Err("Error: size must be >= 2".into());
2183 }
2184 let nbytes = bits.div_ceil(8);
2185 let mut buf = vec![0u8; nbytes];
2186 getrandom::getrandom(&mut buf).map_err(|e| format!("Error: {e}"))?;
2187 let excess = nbytes * 8 - bits;
2188 buf[0] &= 0xffu8 >> excess;
2189 buf[0] |= 0x80u8 >> excess;
2190 let last = nbytes - 1;
2191 buf[last] |= 1;
2192 let start = BigUint::from_bytes_be(&buf);
2193 num_prime::nt_funcs::next_prime(&start, None)
2194 .ok_or_else(|| "Error: prime generation failed".into())
2195}
2196
2197fn argon2_hash(algo: &str, opts: Option<&Value>) -> Result<Vec<u8>, String> {
2201 let o = opts.cloned().ok_or("Error: argon2 options required")?;
2202 let msg = prop_bytes(&o, "message");
2203 let salt = prop_bytes(&o, "nonce");
2204 let secret = prop_bytes(&o, "secret");
2205 let taglen = opt_num(&o, &["tagLength"], 32.0).max(4.0) as usize;
2206 let mem = opt_num(&o, &["memory"], 65536.0) as u32;
2207 let passes = opt_num(&o, &["passes"], 3.0) as u32;
2208 let par = opt_num(&o, &["parallelism"], 4.0) as u32;
2209 let algorithm = match algo.to_ascii_lowercase().as_str() {
2210 "argon2d" => argon2::Algorithm::Argon2d,
2211 "argon2i" => argon2::Algorithm::Argon2i,
2212 _ => argon2::Algorithm::Argon2id,
2213 };
2214 let params =
2215 argon2::Params::new(mem, passes, par, Some(taglen)).map_err(|e| format!("Error: {e}"))?;
2216 let ctx = if secret.is_empty() {
2217 argon2::Argon2::new(algorithm, argon2::Version::V0x13, params)
2218 } else {
2219 argon2::Argon2::new_with_secret(&secret, algorithm, argon2::Version::V0x13, params)
2220 .map_err(|e| format!("Error: {e}"))?
2221 };
2222 let mut out = vec![0u8; taglen];
2223 ctx.hash_password_into(&msg, &salt, &mut out)
2224 .map_err(|e| format!("Error: {e}"))?;
2225 Ok(out)
2226}
2227
2228fn prop_bytes(obj: &Value, key: &str) -> Vec<u8> {
2230 let v = with_host(|h| match h.get(obj) {
2231 Some(JsObj::Object(p)) => p.get(key).cloned(),
2232 _ => None,
2233 });
2234 v.map(|x| val_bytes(&x)).unwrap_or_default()
2235}
2236
2237fn get_random_values(v: Option<&Value>) -> Result<Value, String> {
2241 let ta = v
2242 .cloned()
2243 .ok_or("Error: argument must be an integer-type TypedArray")?;
2244 let tag = super::native_tag(&ta);
2245 if tag.as_deref() == Some("Buffer") {
2246 let len = val_bytes(&ta).len();
2247 let mut rnd = vec![0u8; len];
2248 getrandom::getrandom(&mut rnd).map_err(|e| format!("Error: {e}"))?;
2249 set_obj_bytes_named(&ta, "@@bytes", &rnd);
2250 return Ok(ta);
2251 }
2252 if tag.as_deref() != Some("TypedArray") {
2253 return Err("Error: argument must be an integer-type TypedArray".into());
2254 }
2255 let kind = obj_str(&ta, "@@kind");
2256 if kind.starts_with("Float") {
2257 return Err("Error: The provided ArrayBufferView is of type 'Float', which is not an integer array type".into());
2258 }
2259 let len = with_host(|h| {
2260 if let Some(JsObj::Object(p)) = h.get(&ta) {
2261 if let Some(JsObj::Array(it)) = p.get("@@elems").and_then(|v| h.get(v)) {
2262 return it.len();
2263 }
2264 }
2265 0
2266 });
2267 let bpe = match kind.as_str() {
2268 "Int16Array" | "Uint16Array" => 2,
2269 "Int32Array" | "Uint32Array" => 4,
2270 _ => 1,
2271 };
2272 let mut raw = vec![0u8; len * bpe];
2273 getrandom::getrandom(&mut raw).map_err(|e| format!("Error: {e}"))?;
2274 let elems: Vec<Value> = (0..len)
2275 .map(|i| {
2276 let mut acc: u64 = 0;
2277 for j in 0..bpe {
2278 acc |= (raw[i * bpe + j] as u64) << (8 * j);
2279 }
2280 Value::Float(ta_coerce(&kind, acc))
2281 })
2282 .collect();
2283 with_host(|h| {
2284 let arr = match h.get(&ta) {
2285 Some(JsObj::Object(p)) => p.get("@@elems").cloned(),
2286 _ => None,
2287 };
2288 if let Some(a) = arr {
2289 if let Some(JsObj::Array(items)) = h.get_mut(&a) {
2290 *items = elems;
2291 }
2292 }
2293 });
2294 Ok(ta)
2295}
2296
2297fn ta_coerce(kind: &str, raw: u64) -> f64 {
2299 match kind {
2300 "Int8Array" => (raw as i8) as f64,
2301 "Int16Array" => (raw as i16) as f64,
2302 "Int32Array" => (raw as i32) as f64,
2303 "Uint16Array" => (raw as u16) as f64,
2304 "Uint32Array" => (raw as u32) as f64,
2305 _ => (raw as u8) as f64, }
2307}
2308
2309fn set_obj_bytes_named(recv: &Value, key: &str, bytes: &[u8]) {
2311 with_host(|h| {
2312 let arr = match h.get(recv) {
2313 Some(JsObj::Object(p)) => p.get(key).cloned(),
2314 _ => None,
2315 };
2316 if let Some(a) = arr {
2317 if let Some(JsObj::Array(items)) = h.get_mut(&a) {
2318 *items = bytes.iter().map(|b| Value::Float(*b as f64)).collect();
2319 }
2320 }
2321 });
2322}
2323
2324pub fn key_object_instance_call(
2328 recv: &Value,
2329 method: &str,
2330 args: &[Value],
2331) -> Result<Value, String> {
2332 match method {
2333 "export" => {
2334 let secret = obj_bytes(recv, "@@secret");
2336 if !secret.is_empty() {
2337 return Ok(super::buffer::from_bytes(&secret));
2338 }
2339 let pem = obj_str(recv, "@@pem");
2340 let format = args
2341 .first()
2342 .map(|o| opt_str(o, "format"))
2343 .filter(|s| !s.is_empty())
2344 .unwrap_or_else(|| "pem".into());
2345 if format == "der" {
2346 Ok(super::buffer::from_bytes(&pem_body(&pem)))
2347 } else {
2348 Ok(with_host(|h| h.new_str(pem)))
2349 }
2350 }
2351 "equals" => {
2352 let other = args.first().map(key_material).unwrap_or_default();
2353 let mine = obj_str(recv, "@@pem").into_bytes();
2354 Ok(Value::Bool(mine == other))
2355 }
2356 _ => Err(crate::host::type_error(&format!(
2357 "keyObject.{method} is not a function"
2358 ))),
2359 }
2360}
2361
2362pub fn construct_x509(args: &[Value]) -> Result<Value, String> {
2366 use x509_cert::der::{Decode, DecodePem, Encode};
2367 let bytes = val_bytes_at(args, 0);
2368 let is_pem = bytes.starts_with(b"-----BEGIN");
2369 let cert = if is_pem {
2370 x509_cert::Certificate::from_pem(&bytes).map_err(|e| format!("Error: {e}"))?
2371 } else {
2372 x509_cert::Certificate::from_der(&bytes).map_err(|e| format!("Error: {e}"))?
2373 };
2374 let der = cert.to_der().map_err(|e| format!("Error: {e}"))?;
2376 let fp = {
2377 let d = digest("sha1", &der);
2378 d.iter()
2379 .map(|b| format!("{b:02X}"))
2380 .collect::<Vec<_>>()
2381 .join(":")
2382 };
2383 let subject = x509_name_node(&cert.tbs_certificate.subject.to_string());
2384 let issuer = x509_name_node(&cert.tbs_certificate.issuer.to_string());
2385 let not_before = x509_time(&cert.tbs_certificate.validity.not_before);
2386 let not_after = x509_time(&cert.tbs_certificate.validity.not_after);
2387 let serial = cert
2388 .tbs_certificate
2389 .serial_number
2390 .as_bytes()
2391 .iter()
2392 .map(|b| format!("{b:02X}"))
2393 .collect::<String>();
2394 let spki_der = cert
2395 .tbs_certificate
2396 .subject_public_key_info
2397 .to_der()
2398 .map_err(|e| format!("Error: {e}"))?;
2399 let pub_pem = pem_wrap("PUBLIC KEY", &spki_der);
2400 let pub_key =
2401 create_public_key(Some(&with_host(|h| h.new_str(pub_pem)))).unwrap_or(Value::Undef);
2402 let cert_pem = pem_wrap("CERTIFICATE", &der);
2403 let raw = super::buffer::from_bytes(&der);
2404 Ok(with_host(|h| {
2405 let mut m = IndexMap::new();
2406 m.insert("@@native".into(), h.new_str("X509Certificate"));
2407 m.insert("subject".into(), h.new_str(subject));
2408 m.insert("issuer".into(), h.new_str(issuer));
2409 m.insert("validFrom".into(), h.new_str(not_before));
2410 m.insert("validTo".into(), h.new_str(not_after));
2411 m.insert("serialNumber".into(), h.new_str(serial));
2412 m.insert("fingerprint".into(), h.new_str(fp));
2413 m.insert("publicKey".into(), pub_key);
2414 m.insert("raw".into(), raw);
2415 m.insert("@@pem".into(), h.new_str(cert_pem));
2416 h.new_object(m)
2417 }))
2418}
2419
2420pub fn x509_instance_call(recv: &Value, method: &str, _args: &[Value]) -> Result<Value, String> {
2422 match method {
2423 "toString" => Ok(with_host(|h| h.new_str(obj_str(recv, "@@pem")))),
2424 _ => Err(crate::host::type_error(&format!(
2425 "x509Certificate.{method} is not a function"
2426 ))),
2427 }
2428}
2429
2430fn x509_name_node(rfc4514: &str) -> String {
2433 rfc4514
2434 .split(',')
2435 .map(|s| s.trim())
2436 .rev()
2437 .collect::<Vec<_>>()
2438 .join("\n")
2439}
2440
2441fn x509_time(t: &x509_cert::time::Time) -> String {
2443 const MON: [&str; 12] = [
2444 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
2445 ];
2446 let dt = t.to_date_time();
2447 let mon = MON
2448 .get(dt.month().saturating_sub(1) as usize)
2449 .copied()
2450 .unwrap_or("Jan");
2451 format!(
2452 "{} {:2} {:02}:{:02}:{:02} {} GMT",
2453 mon,
2454 dt.day(),
2455 dt.hour(),
2456 dt.minutes(),
2457 dt.seconds(),
2458 dt.year()
2459 )
2460}
2461
2462const MODP1: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF";
2464const MODP2: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF";
2465const MODP5: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
2466const MODP14: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";
2467const MODP15: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
2468const MODP16: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF";
2469const MODP17: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF";
2470const MODP18: &str = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF";