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 final int lenght = array.getByteLength() / array.getBytesPerElement();
89 for (int i = 0; i < lenght; i++) {
90 array.put(i, array, RANDOM.nextInt());
91 }
92 return array;
93 }
94
95
96
97
98
99 @JsxGetter
100 public SubtleCrypto getSubtle() {
101 final SubtleCrypto stuble = new SubtleCrypto();
102 final Window window = getWindow();
103 stuble.setParentScope(window);
104 stuble.setPrototype(window.getPrototype(SubtleCrypto.class));
105 return stuble;
106 }
107
108
109
110
111 @JsxFunction
112 public String randomUUID() {
113
114
115 final byte[] bytes = new byte[16];
116 RANDOM.nextBytes(bytes);
117
118
119 bytes[6] = (byte) (bytes[6] | 0b01000000);
120 bytes[6] = (byte) (bytes[6] & 0b01001111);
121
122 bytes[8] = (byte) (bytes[8] | 0b10000000);
123 bytes[8] = (byte) (bytes[6] & 0b10111111);
124
125 final StringBuilder result = new StringBuilder()
126 .append(toHex(bytes[0]))
127 .append(toHex(bytes[1]))
128 .append(toHex(bytes[2]))
129 .append(toHex(bytes[3]))
130 .append('-')
131 .append(toHex(bytes[4]))
132 .append(toHex(bytes[5]))
133 .append('-')
134 .append(toHex(bytes[6]))
135 .append(toHex(bytes[7]))
136 .append('-')
137 .append(toHex(bytes[8]))
138 .append(toHex(bytes[9]))
139 .append('-')
140 .append(toHex(bytes[10]))
141 .append(toHex(bytes[11]))
142 .append(toHex(bytes[12]))
143 .append(toHex(bytes[13]))
144 .append(toHex(bytes[14]))
145 .append(toHex(bytes[15]));
146 return result.toString();
147 }
148
149 private static String toHex(final byte b) {
150 return String.format("%02X ", b).trim().toLowerCase(Locale.ROOT);
151 }
152 }