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.math.BigInteger;
18 import java.nio.ByteBuffer;
19 import java.util.Set;
20
21 import org.htmlunit.corejs.javascript.Scriptable;
22 import org.htmlunit.corejs.javascript.ScriptableObject;
23 import org.htmlunit.corejs.javascript.VarScope;
24 import org.htmlunit.corejs.javascript.typedarrays.NativeArrayBuffer;
25 import org.htmlunit.corejs.javascript.typedarrays.NativeArrayBufferView;
26 import org.htmlunit.corejs.javascript.typedarrays.NativeUint8Array;
27 import org.htmlunit.javascript.JavaScriptEngine;
28
29
30
31
32
33
34
35
36 final class RsaHashedKeyAlgorithm implements KeyAlgorithm {
37
38 static final Set<String> SUPPORTED_NAMES = Set.of("RSASSA-PKCS1-v1_5", "RSA-PSS", "RSA-OAEP");
39 static final Set<String> SUPPORTED_HASH_ALGORITHMS = Set.of("SHA-1", "SHA-256", "SHA-384", "SHA-512");
40
41 private final String name_;
42 private final int modulusLength_;
43 private final byte[] publicExponent_;
44 private final String hash_;
45
46 RsaHashedKeyAlgorithm(final String name, final int modulusLength,
47 final byte[] publicExponent, final String hash) {
48 if (!SUPPORTED_NAMES.contains(name)) {
49 throw new UnsupportedOperationException("RSA " + name);
50 }
51 name_ = name;
52 modulusLength_ = modulusLength;
53
54 if (publicExponent == null) {
55 throw new IllegalArgumentException("Data provided to an operation does not meet requirements");
56 }
57 publicExponent_ = publicExponent.clone();
58
59 if (!SUPPORTED_HASH_ALGORITHMS.contains(hash)) {
60 throw new UnsupportedOperationException("RSA hash " + hash);
61 }
62 hash_ = hash;
63 }
64
65
66
67
68
69
70
71 static RsaHashedKeyAlgorithm from(final Scriptable keyGenParams) {
72 final String name = SubtleCrypto.resolveAlgorithmName(keyGenParams);
73
74 final int modulusLength = (int) SubtleCrypto.getRequiredNumber(keyGenParams, "modulusLength");
75
76 final byte[] publicExponent = extractBytes(SubtleCrypto.getRequiredMember(keyGenParams, "publicExponent"));
77 if (publicExponent == null) {
78 throw JavaScriptEngine.typeError("The member 'publicExponent' is not a Uint8Array");
79 }
80
81 final String hash = SubtleCrypto.resolveAlgorithmName(SubtleCrypto.getRequiredMember(keyGenParams, "hash"));
82
83 return new RsaHashedKeyAlgorithm(name, modulusLength, publicExponent, hash);
84 }
85
86 private static byte[] extractBytes(final Object value) {
87 if (value instanceof NativeArrayBuffer || value instanceof NativeArrayBufferView) {
88 final ByteBuffer bb = SubtleCrypto.asByteBuffer(value);
89 final byte[] result = new byte[bb.remaining()];
90 bb.get(result);
91 return result;
92 }
93 return null;
94 }
95
96 static boolean isSupported(final String name) {
97 return SUPPORTED_NAMES.contains(name);
98 }
99
100 @Override
101 public String getName() {
102 return name_;
103 }
104
105 int getModulusLength() {
106 return modulusLength_;
107 }
108
109 byte[] getPublicExponent() {
110 return publicExponent_.clone();
111 }
112
113
114
115
116
117
118 BigInteger getPublicExponentAsBigInteger() {
119 return new BigInteger(1, publicExponent_);
120 }
121
122 String getHash() {
123 return hash_;
124 }
125
126
127
128
129
130
131 String getJavaHash() {
132 return hash_.replace("-", "");
133 }
134
135
136
137
138
139
140
141
142 @Override
143 public Scriptable toScriptableObject(final VarScope scope) {
144 final Scriptable hashObj = JavaScriptEngine.newObject(scope);
145 ScriptableObject.putProperty(hashObj, "name", getHash());
146
147 final NativeUint8Array uint8Array = JavaScriptEngine.newUint8Array(scope, publicExponent_);
148
149 final Scriptable algorithm = JavaScriptEngine.newObject(scope);
150 ScriptableObject.putProperty(algorithm, "name", getName());
151 ScriptableObject.putProperty(algorithm, "hash", hashObj);
152 ScriptableObject.putProperty(algorithm, "modulusLength", getModulusLength());
153 ScriptableObject.putProperty(algorithm, "publicExponent", uint8Array);
154 return algorithm;
155 }
156 }