1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.crypto;
16
17 import java.security.SecureRandom;
18 import java.util.Locale;
19
20 import org.htmlunit.corejs.javascript.typedarrays.NativeTypedArrayView;
21 import org.htmlunit.javascript.HtmlUnitScriptable;
22 import org.htmlunit.javascript.JavaScriptEngine;
23 import org.htmlunit.javascript.configuration.JsxClass;
24 import org.htmlunit.javascript.configuration.JsxConstructor;
25 import org.htmlunit.javascript.configuration.JsxFunction;
26 import org.htmlunit.javascript.configuration.JsxGetter;
27 import org.htmlunit.javascript.host.Window;
28 import org.htmlunit.javascript.host.dom.DOMException;
29
30
31
32
33
34
35
36
37 @JsxClass
38 public class Crypto extends HtmlUnitScriptable {
39
40 static final SecureRandom RANDOM = new SecureRandom();
41
42
43
44
45 public Crypto() {
46 super();
47 }
48
49
50
51
52 @JsxConstructor
53 public void jsConstructor() {
54 throw JavaScriptEngine.typeErrorIllegalConstructor();
55 }
56
57
58
59
60
61 public Crypto(final Window window) {
62 this();
63 setParentScope(window);
64 setPrototype(window.getPrototype(Crypto.class));
65 }
66
67
68
69
70
71
72
73 @JsxFunction
74 public NativeTypedArrayView<?> getRandomValues(final NativeTypedArrayView<?> array) {
75 if (array == null) {
76 throw JavaScriptEngine.typeError("Argument 1 of Crypto.getRandomValues is not an object.");
77 }
78 if (array.getByteLength() > 65_536) {
79 throw JavaScriptEngine.asJavaScriptException(
80 getWindow(),
81 "Error: Failed to execute 'getRandomValues' on 'Crypto': "
82 + "The ArrayBufferView's byte length "
83 + "(" + array.getByteLength() + ") exceeds the number of bytes "
84 + "of entropy available via this API (65536).",
85 DOMException.QUOTA_EXCEEDED_ERR);
86 }
87
88 for (int i = 0; i < array.getByteLength() / array.getBytesPerElement(); i++) {
89 array.put(i, array, RANDOM.nextInt());
90 }
91 return array;
92 }
93
94
95
96
97
98 @JsxGetter
99 public SubtleCrypto getSubtle() {
100 final SubtleCrypto stuble = new SubtleCrypto();
101 final Window window = getWindow();
102 stuble.setParentScope(window);
103 stuble.setPrototype(window.getPrototype(SubtleCrypto.class));
104 return stuble;
105 }
106
107
108
109
110 @JsxFunction
111 public String randomUUID() {
112
113
114 final byte[] bytes = new byte[16];
115 RANDOM.nextBytes(bytes);
116
117
118 bytes[6] = (byte) (bytes[6] | 0b01000000);
119 bytes[6] = (byte) (bytes[6] & 0b01001111);
120
121 bytes[8] = (byte) (bytes[8] | 0b10000000);
122 bytes[8] = (byte) (bytes[6] & 0b10111111);
123
124 final StringBuilder result = new StringBuilder()
125 .append(toHex(bytes[0]))
126 .append(toHex(bytes[1]))
127 .append(toHex(bytes[2]))
128 .append(toHex(bytes[3]))
129 .append('-')
130 .append(toHex(bytes[4]))
131 .append(toHex(bytes[5]))
132 .append('-')
133 .append(toHex(bytes[6]))
134 .append(toHex(bytes[7]))
135 .append('-')
136 .append(toHex(bytes[8]))
137 .append(toHex(bytes[9]))
138 .append('-')
139 .append(toHex(bytes[10]))
140 .append(toHex(bytes[11]))
141 .append(toHex(bytes[12]))
142 .append(toHex(bytes[13]))
143 .append(toHex(bytes[14]))
144 .append(toHex(bytes[15]));
145 return result.toString();
146 }
147
148 private static String toHex(final byte b) {
149 return String.format("%02X ", b).trim().toLowerCase(Locale.ROOT);
150 }
151 }