script_webcrypto/crypto.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::context::JSContext;
7use js::jsapi::Type;
8use js::rust::CustomAutoRooterGuard;
9use js::typedarray::{ArrayBufferView, HeapArrayBufferView};
10use jstraceable_derive::JSTraceable;
11use malloc_size_of_derive::MallocSizeOf;
12use script_bindings::DomTypes;
13use script_bindings::buffer_source::HeapBufferSource;
14use script_bindings::codegen::GenericBindings::CryptoBinding::{CryptoMethods, Wrap as CryptoWrap};
15use script_bindings::dom::MutNullableDom;
16use script_bindings::error::{Error, Fallible};
17use script_bindings::reflector::{DomGlobalGeneric, Reflector, reflect_dom_object_with_wrap};
18use script_bindings::root::DomRoot;
19use script_bindings::str::DOMString;
20use script_bindings::trace::RootedTraceableBox;
21use uuid::Uuid;
22
23use crate::subtlecrypto::SubtleCrypto;
24use crate::traits::Equivalence;
25
26/// <https://w3c.github.io/webcrypto/#crypto-interface>
27#[dom_struct]
28pub struct Crypto<D: DomTypes> {
29 reflector_: Reflector,
30 subtle: MutNullableDom<SubtleCrypto<D>>,
31}
32
33impl<D> Crypto<D>
34where
35 D: Equivalence,
36{
37 fn new_inherited() -> Crypto<D> {
38 Crypto {
39 reflector_: Reflector::new(),
40 subtle: MutNullableDom::default(),
41 }
42 }
43
44 pub fn new(cx: &mut JSContext, global: &D::GlobalScope) -> DomRoot<Crypto<D>> {
45 reflect_dom_object_with_wrap::<D, _, _>(
46 cx,
47 Box::new(Crypto::new_inherited()),
48 global,
49 CryptoWrap::<D>,
50 )
51 }
52}
53
54impl<D> CryptoMethods<D> for Crypto<D>
55where
56 D: Equivalence,
57 Self: DomGlobalGeneric<D>,
58{
59 /// <https://w3c.github.io/webcrypto/#dfn-Crypto-attribute-subtle>
60 fn Subtle(&self, cx: &mut JSContext) -> DomRoot<SubtleCrypto<D>> {
61 self.subtle
62 .or_init(|| SubtleCrypto::new(cx, &*self.global_from_reflector()))
63 }
64
65 /// <https://w3c.github.io/webcrypto/#Crypto-method-getRandomValues>
66 fn GetRandomValues(
67 &self,
68 cx: &mut JSContext,
69 mut array: CustomAutoRooterGuard<ArrayBufferView>,
70 ) -> Fallible<RootedTraceableBox<HeapArrayBufferView>> {
71 // Step 1. If array is not an Int8Array, Uint8Array, Uint8ClampedArray, Int16Array,
72 // Uint16Array, Int32Array, Uint32Array, BigInt64Array, or BigUint64Array, then throw a
73 // TypeMismatchError and terminate the algorithm.
74 if !matches!(
75 array.get_array_type(),
76 Type::Int8 |
77 Type::Uint8 |
78 Type::Uint8Clamped |
79 Type::Int16 |
80 Type::Uint16 |
81 Type::Int32 |
82 Type::Uint32 |
83 Type::BigInt64 |
84 Type::BigUint64
85 ) {
86 return Err(Error::TypeMismatch(Some(
87 "The array must be an integer-based TypedArray".into(),
88 )));
89 }
90
91 // Step 2. Let byteLength be the byte length of array.
92 // Step 3. If byteLength is greater than 65536, throw a QuotaExceededError and terminate the
93 // algorithm.
94 // Step 4. Let bytes be a byte sequence of length byteLength.
95 let bytes = array.as_mut_slice_safe(cx.no_gc()).unwrap_or_default();
96 let byte_length = bytes.len();
97 if byte_length > 65536 {
98 return Err(Error::QuotaExceeded {
99 quota: None,
100 requested: None,
101 });
102 }
103
104 // Step 5. Fill bytes with cryptographically secure random bytes.
105 // Step 6. Write bytes into array.
106 rand::fill(bytes);
107
108 // Step 7. Return array.
109 let array = HeapBufferSource::from_view(cx, array);
110 array.get_typed_array().map_err(|_| Error::JSFailed)
111 }
112
113 /// <https://w3c.github.io/webcrypto/#Crypto-method-randomUUID>
114 fn RandomUUID(&self) -> DOMString {
115 // Step 1. Let bytes be a byte sequence of length 16.
116 // Step 2. Fill bytes with cryptographically secure random bytes.
117 // Step 3. Set the 4 most significant bits of bytes[6], which represent the UUID version, to 0100.
118 // Step 4. Set the 2 most significant bits of bytes[8], which represent the UUID variant, to 10.
119 // Step 5.
120 // Return the string concatenation of «
121 // hexadecimal representation of bytes[0], hexadecimal representation of bytes[1],
122 // hexadecimal representation of bytes[2], hexadecimal representation of bytes[3],
123 // "-",
124 // hexadecimal representation of bytes[4], hexadecimal representation of bytes[5],
125 // "-",
126 // hexadecimal representation of bytes[6], hexadecimal representation of bytes[7],
127 // "-",
128 // hexadecimal representation of bytes[8], hexadecimal representation of bytes[9],
129 // "-",
130 // hexadecimal representation of bytes[10], hexadecimal representation of bytes[11],
131 // hexadecimal representation of bytes[12], hexadecimal representation of bytes[13],
132 // hexadecimal representation of bytes[14], hexadecimal representation of bytes[15]
133 // ».
134 let uuid = Uuid::new_v4();
135 uuid.hyphenated()
136 .encode_lower(&mut Uuid::encode_buffer())
137 .to_owned()
138 .into()
139 }
140}