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