Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java
41161 views
1
/*
2
* Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.ec;
27
28
import sun.security.ec.point.AffinePoint;
29
import sun.security.ec.point.Point;
30
import sun.security.util.ArrayUtil;
31
import sun.security.util.CurveDB;
32
import sun.security.util.NamedCurve;
33
import sun.security.util.math.ImmutableIntegerModuloP;
34
import sun.security.util.math.IntegerFieldModuloP;
35
import sun.security.util.math.MutableIntegerModuloP;
36
import sun.security.util.math.SmallValue;
37
38
import javax.crypto.KeyAgreementSpi;
39
import javax.crypto.SecretKey;
40
import javax.crypto.ShortBufferException;
41
import javax.crypto.spec.SecretKeySpec;
42
import java.math.BigInteger;
43
import java.security.InvalidAlgorithmParameterException;
44
import java.security.InvalidKeyException;
45
import java.security.Key;
46
import java.security.NoSuchAlgorithmException;
47
import java.security.PrivateKey;
48
import java.security.SecureRandom;
49
import java.security.interfaces.ECPrivateKey;
50
import java.security.interfaces.ECPublicKey;
51
import java.security.spec.AlgorithmParameterSpec;
52
import java.security.spec.ECParameterSpec;
53
import java.security.spec.EllipticCurve;
54
import java.util.Optional;
55
56
/**
57
* KeyAgreement implementation for ECDH.
58
*
59
* @since 1.7
60
*/
61
public final class ECDHKeyAgreement extends KeyAgreementSpi {
62
63
// private key, if initialized
64
private ECPrivateKey privateKey;
65
ECOperations privateKeyOps;
66
67
// public key, non-null between doPhase() & generateSecret() only
68
private ECPublicKey publicKey;
69
70
// length of the secret to be derived
71
private int secretLen;
72
73
/**
74
* Constructs a new ECDHKeyAgreement.
75
*/
76
public ECDHKeyAgreement() {
77
}
78
79
// Generic init
80
private void init(Key key) throws
81
InvalidKeyException, InvalidAlgorithmParameterException {
82
if (!(key instanceof PrivateKey)) {
83
throw new InvalidKeyException("Key must be instance of PrivateKey");
84
}
85
privateKey = (ECPrivateKey)ECKeyFactory.toECKey(key);
86
publicKey = null;
87
Optional<ECOperations> opsOpt =
88
ECOperations.forParameters(privateKey.getParams());
89
if (opsOpt.isEmpty()) {
90
NamedCurve nc = CurveDB.lookup(privateKey.getParams());
91
throw new InvalidAlgorithmParameterException(
92
"Curve not supported: " + (nc != null ? nc.toString() :
93
"unknown"));
94
}
95
privateKeyOps = opsOpt.get();
96
}
97
98
// see JCE spec
99
@Override
100
protected void engineInit(Key key, SecureRandom random)
101
throws InvalidKeyException {
102
try {
103
init(key);
104
} catch (InvalidAlgorithmParameterException e) {
105
throw new InvalidKeyException(e);
106
}
107
}
108
109
// see JCE spec
110
@Override
111
protected void engineInit(Key key, AlgorithmParameterSpec params,
112
SecureRandom random) throws InvalidKeyException,
113
InvalidAlgorithmParameterException {
114
if (params != null) {
115
throw new InvalidAlgorithmParameterException
116
("Parameters not supported");
117
}
118
init(key);
119
}
120
121
// see JCE spec
122
@Override
123
protected Key engineDoPhase(Key key, boolean lastPhase)
124
throws InvalidKeyException, IllegalStateException {
125
if (privateKey == null) {
126
throw new IllegalStateException("Not initialized");
127
}
128
if (publicKey != null) {
129
throw new IllegalStateException("Phase already executed");
130
}
131
if (!lastPhase) {
132
throw new IllegalStateException
133
("Only two party agreement supported, lastPhase must be true");
134
}
135
if (!(key instanceof ECPublicKey)) {
136
throw new InvalidKeyException
137
("Key must be a PublicKey with algorithm EC");
138
}
139
140
this.publicKey = (ECPublicKey) key;
141
142
int keyLenBits =
143
publicKey.getParams().getCurve().getField().getFieldSize();
144
secretLen = (keyLenBits + 7) >> 3;
145
146
// Validate public key
147
validate(privateKeyOps, publicKey);
148
149
return null;
150
}
151
152
// Verify that x and y are integers in the interval [0, p - 1].
153
private static void validateCoordinate(BigInteger c, BigInteger mod)
154
throws InvalidKeyException{
155
if (c.compareTo(BigInteger.ZERO) < 0) {
156
throw new InvalidKeyException("Invalid coordinate");
157
}
158
159
if (c.compareTo(mod) >= 0) {
160
throw new InvalidKeyException("Invalid coordinate");
161
}
162
}
163
164
// Check whether a public key is valid, following the ECC
165
// Full Public-key Validation Routine (See section 5.6.2.3.3,
166
// NIST SP 800-56A Revision 3).
167
private static void validate(ECOperations ops, ECPublicKey key)
168
throws InvalidKeyException {
169
170
ECParameterSpec spec = key.getParams();
171
172
// Note: Per the NIST 800-56A specification, it is required
173
// to verify that the public key is not the identity element
174
// (point of infinity). However, the point of infinity has no
175
// affine coordinates, although the point of infinity could
176
// be encoded. Per IEEE 1363.3-2013 (see section A.6.4.1),
177
// the point of inifinity is represented by a pair of
178
// coordinates (x, y) not on the curve. For EC prime finite
179
// field (q = p^m), the point of infinity is (0, 0) unless
180
// b = 0; in which case it is (0, 1).
181
//
182
// It means that this verification could be covered by the
183
// validation that the public key is on the curve. As will be
184
// verified in the following steps.
185
186
// Ensure that integers are in proper range.
187
BigInteger x = key.getW().getAffineX();
188
BigInteger y = key.getW().getAffineY();
189
190
BigInteger p = ops.getField().getSize();
191
validateCoordinate(x, p);
192
validateCoordinate(y, p);
193
194
// Ensure the point is on the curve.
195
EllipticCurve curve = spec.getCurve();
196
BigInteger rhs = x.modPow(BigInteger.valueOf(3), p).add(curve.getA()
197
.multiply(x)).add(curve.getB()).mod(p);
198
BigInteger lhs = y.modPow(BigInteger.valueOf(2), p).mod(p);
199
if (!rhs.equals(lhs)) {
200
throw new InvalidKeyException("Point is not on curve");
201
}
202
203
// Check the order of the point.
204
//
205
// Compute nQ (using elliptic curve arithmetic), and verify that
206
// nQ is the the identity element.
207
ImmutableIntegerModuloP xElem = ops.getField().getElement(x);
208
ImmutableIntegerModuloP yElem = ops.getField().getElement(y);
209
AffinePoint affP = new AffinePoint(xElem, yElem);
210
byte[] order = spec.getOrder().toByteArray();
211
ArrayUtil.reverse(order);
212
Point product = ops.multiply(affP, order);
213
if (!ops.isNeutral(product)) {
214
throw new InvalidKeyException("Point has incorrect order");
215
}
216
}
217
218
// see JCE spec
219
@Override
220
protected byte[] engineGenerateSecret() throws IllegalStateException {
221
if ((privateKey == null) || (publicKey == null)) {
222
throw new IllegalStateException("Not initialized correctly");
223
}
224
225
byte[] result;
226
try {
227
result = deriveKeyImpl(privateKey, privateKeyOps, publicKey);
228
} catch (Exception e) {
229
throw new IllegalStateException(e);
230
}
231
publicKey = null;
232
return result;
233
}
234
235
// see JCE spec
236
@Override
237
protected int engineGenerateSecret(byte[] sharedSecret, int
238
offset) throws IllegalStateException, ShortBufferException {
239
if (secretLen > sharedSecret.length - offset) {
240
throw new ShortBufferException("Need " + secretLen
241
+ " bytes, only " + (sharedSecret.length - offset)
242
+ " available");
243
}
244
byte[] secret = engineGenerateSecret();
245
System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
246
return secret.length;
247
}
248
249
// see JCE spec
250
@Override
251
protected SecretKey engineGenerateSecret(String algorithm)
252
throws IllegalStateException, NoSuchAlgorithmException,
253
InvalidKeyException {
254
if (algorithm == null) {
255
throw new NoSuchAlgorithmException("Algorithm must not be null");
256
}
257
if (!(algorithm.equals("TlsPremasterSecret"))) {
258
throw new NoSuchAlgorithmException
259
("Only supported for algorithm TlsPremasterSecret");
260
}
261
return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
262
}
263
264
private static
265
byte[] deriveKeyImpl(ECPrivateKey priv, ECOperations ops,
266
ECPublicKey pubKey) throws InvalidKeyException {
267
268
IntegerFieldModuloP field = ops.getField();
269
// convert s array into field element and multiply by the cofactor
270
MutableIntegerModuloP scalar = field.getElement(priv.getS()).mutable();
271
SmallValue cofactor =
272
field.getSmallValue(priv.getParams().getCofactor());
273
scalar.setProduct(cofactor);
274
int keySize =
275
(priv.getParams().getCurve().getField().getFieldSize() + 7) / 8;
276
ImmutableIntegerModuloP x =
277
field.getElement(pubKey.getW().getAffineX());
278
ImmutableIntegerModuloP y =
279
field.getElement(pubKey.getW().getAffineY());
280
Point product = ops.multiply(new AffinePoint(x, y),
281
scalar.asByteArray(keySize));
282
if (ops.isNeutral(product)) {
283
throw new InvalidKeyException("Product is zero");
284
}
285
286
byte[] result = product.asAffine().getX().asByteArray(keySize);
287
ArrayUtil.reverse(result);
288
289
return result;
290
}
291
}
292
293