feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
94
jdkSrc/jdk8/sun/security/rsa/MGF1.java
Normal file
94
jdkSrc/jdk8/sun/security/rsa/MGF1.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* This class implements the MGF1 mask generation function defined in PKCS#1
|
||||
* v2.2 B.2.1 (https://tools.ietf.org/html/rfc8017#appendix-B.2.1). A mask
|
||||
* generation function takes an octet string of variable length and a
|
||||
* desired output length as input and outputs an octet string of the
|
||||
* desired length. MGF1 is a mask generation function based on a hash
|
||||
* function, i.e. message digest algorithm.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class MGF1 {
|
||||
|
||||
private final MessageDigest md;
|
||||
|
||||
/**
|
||||
* Construct an instance of MGF1 based on the specified digest algorithm.
|
||||
*/
|
||||
MGF1(String mdAlgo) throws NoSuchAlgorithmException {
|
||||
this.md = MessageDigest.getInstance(mdAlgo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the specified seed bytes, generate the mask, xor the mask
|
||||
* with the specified output buffer and store the result into the
|
||||
* output buffer (essentially replaced in place).
|
||||
*
|
||||
* @param seed the buffer holding the seed bytes
|
||||
* @param seedOfs the index of the seed bytes
|
||||
* @param seedLen the length of the seed bytes to be used by MGF1
|
||||
* @param maskLen the intended length of the generated mask
|
||||
* @param out the output buffer holding the mask
|
||||
* @param outOfs the index of the output buffer for the mask
|
||||
*/
|
||||
void generateAndXor(byte[] seed, int seedOfs, int seedLen, int maskLen,
|
||||
byte[] out, int outOfs) throws RuntimeException {
|
||||
byte[] C = new byte[4]; // 32 bit counter
|
||||
byte[] digest = new byte[md.getDigestLength()];
|
||||
while (maskLen > 0) {
|
||||
md.update(seed, seedOfs, seedLen);
|
||||
md.update(C);
|
||||
try {
|
||||
md.digest(digest, 0, digest.length);
|
||||
} catch (DigestException e) {
|
||||
// should never happen
|
||||
throw new RuntimeException(e.toString());
|
||||
}
|
||||
for (int i = 0; (i < digest.length) && (maskLen > 0); maskLen--) {
|
||||
out[outOfs++] ^= digest[i++];
|
||||
}
|
||||
if (maskLen > 0) {
|
||||
// increment counter
|
||||
for (int i = C.length - 1; (++C[i] == 0) && (i > 0); i--) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this MGF1 instance, i.e. "MGF1" followed by the
|
||||
* digest algorithm it based on.
|
||||
*/
|
||||
String getName() {
|
||||
return "MGF1" + md.getAlgorithm();
|
||||
}
|
||||
}
|
||||
279
jdkSrc/jdk8/sun/security/rsa/PSSParameters.java
Normal file
279
jdkSrc/jdk8/sun/security/rsa/PSSParameters.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.*;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.*;
|
||||
import java.security.AlgorithmParametersSpi;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.InvalidParameterSpecException;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
import java.security.spec.PSSParameterSpec;
|
||||
import static java.security.spec.PSSParameterSpec.DEFAULT;
|
||||
|
||||
/**
|
||||
* This class implements the PSS parameters used with the RSA
|
||||
* signatures in PSS padding. Here is its ASN.1 definition:
|
||||
* RSASSA-PSS-params ::= SEQUENCE {
|
||||
* hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
|
||||
* maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
|
||||
* saltLength [2] INTEGER DEFAULT 20
|
||||
* trailerField [3] TrailerField DEFAULT trailerFieldBC
|
||||
* }
|
||||
*
|
||||
* @author Valerie Peng
|
||||
*
|
||||
*/
|
||||
|
||||
public final class PSSParameters extends AlgorithmParametersSpi {
|
||||
|
||||
private PSSParameterSpec spec;
|
||||
|
||||
public PSSParameters() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(AlgorithmParameterSpec paramSpec)
|
||||
throws InvalidParameterSpecException {
|
||||
if (!(paramSpec instanceof PSSParameterSpec)) {
|
||||
throw new InvalidParameterSpecException
|
||||
("Inappropriate parameter specification");
|
||||
}
|
||||
PSSParameterSpec spec = (PSSParameterSpec) paramSpec;
|
||||
|
||||
String mgfName = spec.getMGFAlgorithm();
|
||||
if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1")) {
|
||||
throw new InvalidParameterSpecException("Unsupported mgf " +
|
||||
mgfName + "; MGF1 only");
|
||||
}
|
||||
AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
|
||||
if (!(mgfSpec instanceof MGF1ParameterSpec)) {
|
||||
throw new InvalidParameterSpecException("Inappropriate mgf " +
|
||||
"parameters; non-null MGF1ParameterSpec only");
|
||||
}
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(byte[] encoded) throws IOException {
|
||||
// first initialize with the DEFAULT values before
|
||||
// retrieving from the encoding bytes
|
||||
String mdName = DEFAULT.getDigestAlgorithm();
|
||||
MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) DEFAULT.getMGFParameters();
|
||||
int saltLength = DEFAULT.getSaltLength();
|
||||
int trailerField = DEFAULT.getTrailerField();
|
||||
|
||||
DerInputStream der = new DerInputStream(encoded);
|
||||
DerValue[] datum = der.getSequence(4);
|
||||
|
||||
for (DerValue d : datum) {
|
||||
if (d.isContextSpecific((byte) 0x00)) {
|
||||
// hash algid
|
||||
mdName = AlgorithmId.parse
|
||||
(d.data.getDerValue()).getName();
|
||||
} else if (d.isContextSpecific((byte) 0x01)) {
|
||||
// mgf algid
|
||||
AlgorithmId val = AlgorithmId.parse(d.data.getDerValue());
|
||||
if (!val.getOID().equals(AlgorithmId.mgf1_oid)) {
|
||||
throw new IOException("Only MGF1 mgf is supported");
|
||||
}
|
||||
|
||||
byte[] encodedParams = val.getEncodedParams();
|
||||
if (encodedParams == null) {
|
||||
throw new IOException("Missing MGF1 parameters");
|
||||
}
|
||||
AlgorithmId params = AlgorithmId.parse(
|
||||
new DerValue(encodedParams));
|
||||
String mgfDigestName = params.getName();
|
||||
switch (mgfDigestName) {
|
||||
case "SHA-1":
|
||||
mgfSpec = MGF1ParameterSpec.SHA1;
|
||||
break;
|
||||
case "SHA-224":
|
||||
mgfSpec = MGF1ParameterSpec.SHA224;
|
||||
break;
|
||||
case "SHA-256":
|
||||
mgfSpec = MGF1ParameterSpec.SHA256;
|
||||
break;
|
||||
case "SHA-384":
|
||||
mgfSpec = MGF1ParameterSpec.SHA384;
|
||||
break;
|
||||
case "SHA-512":
|
||||
mgfSpec = MGF1ParameterSpec.SHA512;
|
||||
break;
|
||||
case "SHA-512/224":
|
||||
mgfSpec = MGF1ParameterSpec.SHA512_224;
|
||||
break;
|
||||
case "SHA-512/256":
|
||||
mgfSpec = MGF1ParameterSpec.SHA512_256;
|
||||
break;
|
||||
default:
|
||||
throw new IOException
|
||||
("Unrecognized message digest algorithm " +
|
||||
mgfDigestName);
|
||||
}
|
||||
} else if (d.isContextSpecific((byte) 0x02)) {
|
||||
// salt length
|
||||
saltLength = d.data.getDerValue().getInteger();
|
||||
if (saltLength < 0) {
|
||||
throw new IOException("Negative value for saltLength");
|
||||
}
|
||||
} else if (d.isContextSpecific((byte) 0x03)) {
|
||||
// trailer field
|
||||
trailerField = d.data.getDerValue().getInteger();
|
||||
if (trailerField != 1) {
|
||||
throw new IOException("Unsupported trailerField value " +
|
||||
trailerField);
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Invalid encoded PSSParameters");
|
||||
}
|
||||
}
|
||||
|
||||
this.spec = new PSSParameterSpec(mdName, "MGF1", mgfSpec,
|
||||
saltLength, trailerField);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(byte[] encoded, String decodingMethod)
|
||||
throws IOException {
|
||||
if ((decodingMethod != null) &&
|
||||
(!decodingMethod.equalsIgnoreCase("ASN.1"))) {
|
||||
throw new IllegalArgumentException("Only support ASN.1 format");
|
||||
}
|
||||
engineInit(encoded);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends AlgorithmParameterSpec>
|
||||
T engineGetParameterSpec(Class<T> paramSpec)
|
||||
throws InvalidParameterSpecException {
|
||||
if (PSSParameterSpec.class.isAssignableFrom(paramSpec)) {
|
||||
return paramSpec.cast(spec);
|
||||
} else {
|
||||
throw new InvalidParameterSpecException
|
||||
("Inappropriate parameter specification");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGetEncoded() throws IOException {
|
||||
return getEncoded(spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGetEncoded(String encMethod) throws IOException {
|
||||
if ((encMethod != null) &&
|
||||
(!encMethod.equalsIgnoreCase("ASN.1"))) {
|
||||
throw new IllegalArgumentException("Only support ASN.1 format");
|
||||
}
|
||||
return engineGetEncoded();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String engineToString() {
|
||||
return spec.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encoding of a {@link PSSParameterSpec} object. This method
|
||||
* is used in this class and {@link AlgorithmId}.
|
||||
*
|
||||
* @param spec a {@code PSSParameterSpec} object
|
||||
* @return its DER encoding
|
||||
* @throws IOException if the name of a MessageDigest or MaskGenAlgorithm
|
||||
* is unsupported
|
||||
*/
|
||||
public static byte[] getEncoded(PSSParameterSpec spec) throws IOException {
|
||||
|
||||
AlgorithmParameterSpec mgfSpec = spec.getMGFParameters();
|
||||
if (!(mgfSpec instanceof MGF1ParameterSpec)) {
|
||||
throw new IOException("Cannot encode " + mgfSpec);
|
||||
}
|
||||
|
||||
MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec)mgfSpec;
|
||||
|
||||
DerOutputStream tmp = new DerOutputStream();
|
||||
DerOutputStream tmp2, tmp3;
|
||||
|
||||
// MD
|
||||
AlgorithmId mdAlgId;
|
||||
try {
|
||||
mdAlgId = AlgorithmId.get(spec.getDigestAlgorithm());
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IOException("AlgorithmId " + spec.getDigestAlgorithm() +
|
||||
" impl not found");
|
||||
}
|
||||
if (!mdAlgId.getOID().equals(AlgorithmId.SHA_oid)) {
|
||||
tmp2 = new DerOutputStream();
|
||||
mdAlgId.derEncode(tmp2);
|
||||
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0),
|
||||
tmp2);
|
||||
}
|
||||
|
||||
// MGF
|
||||
AlgorithmId mgfDigestId;
|
||||
try {
|
||||
mgfDigestId = AlgorithmId.get(mgf1Spec.getDigestAlgorithm());
|
||||
} catch (NoSuchAlgorithmException nase) {
|
||||
throw new IOException("AlgorithmId " +
|
||||
mgf1Spec.getDigestAlgorithm() + " impl not found");
|
||||
}
|
||||
|
||||
if (!mgfDigestId.getOID().equals(AlgorithmId.SHA_oid)) {
|
||||
tmp2 = new DerOutputStream();
|
||||
tmp2.putOID(AlgorithmId.mgf1_oid);
|
||||
mgfDigestId.encode(tmp2);
|
||||
tmp3 = new DerOutputStream();
|
||||
tmp3.write(DerValue.tag_Sequence, tmp2);
|
||||
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 1),
|
||||
tmp3);
|
||||
}
|
||||
|
||||
// SaltLength
|
||||
if (spec.getSaltLength() != 20) {
|
||||
tmp2 = new DerOutputStream();
|
||||
tmp2.putInteger(spec.getSaltLength());
|
||||
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 2),
|
||||
tmp2);
|
||||
}
|
||||
|
||||
// TrailerField
|
||||
if (spec.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
|
||||
tmp2 = new DerOutputStream();
|
||||
tmp2.putInteger(spec.getTrailerField());
|
||||
tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 3),
|
||||
tmp2);
|
||||
}
|
||||
|
||||
// Put all together under a SEQUENCE tag
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.write(DerValue.tag_Sequence, tmp);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
458
jdkSrc/jdk8/sun/security/rsa/RSACore.java
Normal file
458
jdkSrc/jdk8/sun/security/rsa/RSACore.java
Normal file
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.*;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
/**
|
||||
* Core of the RSA implementation. Has code to perform public and private key
|
||||
* RSA operations (with and without CRT for private key ops). Private CRT ops
|
||||
* also support blinding to twart timing attacks.
|
||||
*
|
||||
* The code in this class only does the core RSA operation. Padding and
|
||||
* unpadding must be done externally.
|
||||
*
|
||||
* Note: RSA keys should be at least 512 bits long
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class RSACore {
|
||||
|
||||
// globally enable/disable use of blinding
|
||||
private final static boolean ENABLE_BLINDING = true;
|
||||
|
||||
// cache for blinding parameters. Map<BigInteger, BlindingParameters>
|
||||
// use a weak hashmap so that cached values are automatically cleared
|
||||
// when the modulus is GC'ed
|
||||
private final static Map<BigInteger, BlindingParameters>
|
||||
blindingCache = new WeakHashMap<>();
|
||||
|
||||
private RSACore() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes required to store the magnitude byte[] of
|
||||
* this BigInteger. Do not count a 0x00 byte toByteArray() would
|
||||
* prefix for 2's complement form.
|
||||
*/
|
||||
public static int getByteLength(BigInteger b) {
|
||||
int n = b.bitLength();
|
||||
return (n + 7) >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes required to store the modulus of this
|
||||
* RSA key.
|
||||
*/
|
||||
public static int getByteLength(RSAKey key) {
|
||||
return getByteLength(key.getModulus());
|
||||
}
|
||||
|
||||
// temporary, used by RSACipher and RSAPadding. Move this somewhere else
|
||||
public static byte[] convert(byte[] b, int ofs, int len) {
|
||||
if ((ofs == 0) && (len == b.length)) {
|
||||
return b;
|
||||
} else {
|
||||
byte[] t = new byte[len];
|
||||
System.arraycopy(b, ofs, t, 0, len);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an RSA public key operation.
|
||||
*/
|
||||
public static byte[] rsa(byte[] msg, RSAPublicKey key)
|
||||
throws BadPaddingException {
|
||||
return crypt(msg, key.getModulus(), key.getPublicExponent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an RSA private key operation. Uses CRT if the key is a
|
||||
* CRT key with additional verification check after the signature
|
||||
* is computed.
|
||||
*/
|
||||
@Deprecated
|
||||
public static byte[] rsa(byte[] msg, RSAPrivateKey key)
|
||||
throws BadPaddingException {
|
||||
return rsa(msg, key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an RSA private key operation. Uses CRT if the key is a
|
||||
* CRT key. Set 'verify' to true if this function is used for
|
||||
* generating a signature.
|
||||
*/
|
||||
public static byte[] rsa(byte[] msg, RSAPrivateKey key, boolean verify)
|
||||
throws BadPaddingException {
|
||||
if (key instanceof RSAPrivateCrtKey) {
|
||||
return crtCrypt(msg, (RSAPrivateCrtKey)key, verify);
|
||||
} else {
|
||||
return priCrypt(msg, key.getModulus(), key.getPrivateExponent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA public key ops. Simple modPow().
|
||||
*/
|
||||
private static byte[] crypt(byte[] msg, BigInteger n, BigInteger exp)
|
||||
throws BadPaddingException {
|
||||
BigInteger m = parseMsg(msg, n);
|
||||
BigInteger c = m.modPow(exp, n);
|
||||
return toByteArray(c, getByteLength(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA non-CRT private key operations.
|
||||
*/
|
||||
private static byte[] priCrypt(byte[] msg, BigInteger n, BigInteger exp)
|
||||
throws BadPaddingException {
|
||||
|
||||
BigInteger c = parseMsg(msg, n);
|
||||
BlindingRandomPair brp = null;
|
||||
BigInteger m;
|
||||
if (ENABLE_BLINDING) {
|
||||
brp = getBlindingRandomPair(null, exp, n);
|
||||
c = c.multiply(brp.u).mod(n);
|
||||
m = c.modPow(exp, n);
|
||||
m = m.multiply(brp.v).mod(n);
|
||||
} else {
|
||||
m = c.modPow(exp, n);
|
||||
}
|
||||
|
||||
return toByteArray(m, getByteLength(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* RSA private key operations with CRT. Algorithm and variable naming
|
||||
* are taken from PKCS#1 v2.1, section 5.1.2.
|
||||
*/
|
||||
private static byte[] crtCrypt(byte[] msg, RSAPrivateCrtKey key,
|
||||
boolean verify) throws BadPaddingException {
|
||||
BigInteger n = key.getModulus();
|
||||
BigInteger c0 = parseMsg(msg, n);
|
||||
BigInteger c = c0;
|
||||
BigInteger p = key.getPrimeP();
|
||||
BigInteger q = key.getPrimeQ();
|
||||
BigInteger dP = key.getPrimeExponentP();
|
||||
BigInteger dQ = key.getPrimeExponentQ();
|
||||
BigInteger qInv = key.getCrtCoefficient();
|
||||
BigInteger e = key.getPublicExponent();
|
||||
BigInteger d = key.getPrivateExponent();
|
||||
|
||||
BlindingRandomPair brp;
|
||||
if (ENABLE_BLINDING) {
|
||||
brp = getBlindingRandomPair(e, d, n);
|
||||
c = c.multiply(brp.u).mod(n);
|
||||
}
|
||||
|
||||
// m1 = c ^ dP mod p
|
||||
BigInteger m1 = c.modPow(dP, p);
|
||||
// m2 = c ^ dQ mod q
|
||||
BigInteger m2 = c.modPow(dQ, q);
|
||||
|
||||
// h = (m1 - m2) * qInv mod p
|
||||
BigInteger mtmp = m1.subtract(m2);
|
||||
if (mtmp.signum() < 0) {
|
||||
mtmp = mtmp.add(p);
|
||||
}
|
||||
BigInteger h = mtmp.multiply(qInv).mod(p);
|
||||
|
||||
// m = m2 + q * h
|
||||
BigInteger m = h.multiply(q).add(m2);
|
||||
|
||||
if (ENABLE_BLINDING) {
|
||||
m = m.multiply(brp.v).mod(n);
|
||||
}
|
||||
if (verify && !c0.equals(m.modPow(e, n))) {
|
||||
throw new BadPaddingException("RSA private key operation failed");
|
||||
}
|
||||
|
||||
return toByteArray(m, getByteLength(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the msg into a BigInteger and check against the modulus n.
|
||||
*/
|
||||
private static BigInteger parseMsg(byte[] msg, BigInteger n)
|
||||
throws BadPaddingException {
|
||||
BigInteger m = new BigInteger(1, msg);
|
||||
if (m.compareTo(n) >= 0) {
|
||||
throw new BadPaddingException("Message is larger than modulus");
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the encoding of this BigInteger that is exactly len bytes long.
|
||||
* Prefix/strip off leading 0x00 bytes if necessary.
|
||||
* Precondition: bi must fit into len bytes
|
||||
*/
|
||||
private static byte[] toByteArray(BigInteger bi, int len) {
|
||||
byte[] b = bi.toByteArray();
|
||||
int n = b.length;
|
||||
if (n == len) {
|
||||
return b;
|
||||
}
|
||||
// BigInteger prefixed a 0x00 byte for 2's complement form, remove it
|
||||
if ((n == len + 1) && (b[0] == 0)) {
|
||||
byte[] t = new byte[len];
|
||||
System.arraycopy(b, 1, t, 0, len);
|
||||
Arrays.fill(b, (byte)0);
|
||||
return t;
|
||||
}
|
||||
// must be smaller
|
||||
assert (n < len);
|
||||
byte[] t = new byte[len];
|
||||
System.arraycopy(b, 0, t, (len - n), n);
|
||||
Arrays.fill(b, (byte)0);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters (u,v) for RSA Blinding. This is described in the RSA
|
||||
* Bulletin#2 (Jan 96) and other places:
|
||||
*
|
||||
* ftp://ftp.rsa.com/pub/pdfs/bull-2.pdf
|
||||
*
|
||||
* The standard RSA Blinding decryption requires the public key exponent
|
||||
* (e) and modulus (n), and converts ciphertext (c) to plaintext (p).
|
||||
*
|
||||
* Before the modular exponentiation operation, the input message should
|
||||
* be multiplied by (u (mod n)), and afterward the result is corrected
|
||||
* by multiplying with (v (mod n)). The system should reject messages
|
||||
* equal to (0 (mod n)). That is:
|
||||
*
|
||||
* 1. Generate r between 0 and n-1, relatively prime to n.
|
||||
* 2. Compute x = (c*u) mod n
|
||||
* 3. Compute y = (x^d) mod n
|
||||
* 4. Compute p = (y*v) mod n
|
||||
*
|
||||
* The Java APIs allows for either standard RSAPrivateKey or
|
||||
* RSAPrivateCrtKey RSA keys.
|
||||
*
|
||||
* If the public exponent is available to us (e.g. RSAPrivateCrtKey),
|
||||
* choose a random r, then let (u, v):
|
||||
*
|
||||
* u = r ^ e mod n
|
||||
* v = r ^ (-1) mod n
|
||||
*
|
||||
* The proof follows:
|
||||
*
|
||||
* p = (((c * u) ^ d mod n) * v) mod n
|
||||
* = ((c ^ d) * (u ^ d) * v) mod n
|
||||
* = ((c ^ d) * (r ^ e) ^ d) * (r ^ (-1))) mod n
|
||||
* = ((c ^ d) * (r ^ (e * d)) * (r ^ (-1))) mod n
|
||||
* = ((c ^ d) * (r ^ 1) * (r ^ (-1))) mod n (see below)
|
||||
* = (c ^ d) mod n
|
||||
*
|
||||
* because in RSA cryptosystem, d is the multiplicative inverse of e:
|
||||
*
|
||||
* (r^(e * d)) mod n
|
||||
* = (r ^ 1) mod n
|
||||
* = r mod n
|
||||
*
|
||||
* However, if the public exponent is not available (e.g. RSAPrivateKey),
|
||||
* we mitigate the timing issue by using a similar random number blinding
|
||||
* approach using the private key:
|
||||
*
|
||||
* u = r
|
||||
* v = ((r ^ (-1)) ^ d) mod n
|
||||
*
|
||||
* This returns the same plaintext because:
|
||||
*
|
||||
* p = (((c * u) ^ d mod n) * v) mod n
|
||||
* = ((c ^ d) * (u ^ d) * v) mod n
|
||||
* = ((c ^ d) * (u ^ d) * ((u ^ (-1)) ^d)) mod n
|
||||
* = (c ^ d) mod n
|
||||
*
|
||||
* Computing inverses mod n and random number generation is slow, so
|
||||
* it is often not practical to generate a new random (u, v) pair for
|
||||
* each new exponentiation. The calculation of parameters might even be
|
||||
* subject to timing attacks. However, (u, v) pairs should not be
|
||||
* reused since they themselves might be compromised by timing attacks,
|
||||
* leaving the private exponent vulnerable. An efficient solution to
|
||||
* this problem is update u and v before each modular exponentiation
|
||||
* step by computing:
|
||||
*
|
||||
* u = u ^ 2
|
||||
* v = v ^ 2
|
||||
*
|
||||
* The total performance cost is small.
|
||||
*/
|
||||
private final static class BlindingRandomPair {
|
||||
final BigInteger u;
|
||||
final BigInteger v;
|
||||
|
||||
BlindingRandomPair(BigInteger u, BigInteger v) {
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of blinding parameters for a given RSA key.
|
||||
*
|
||||
* The RSA modulus is usually unique, so we index by modulus in
|
||||
* {@code blindingCache}. However, to protect against the unlikely
|
||||
* case of two keys sharing the same modulus, we also store the public
|
||||
* or the private exponent. This means we cannot cache blinding
|
||||
* parameters for multiple keys that share the same modulus, but
|
||||
* since sharing moduli is fundamentally broken and insecure, this
|
||||
* does not matter.
|
||||
*/
|
||||
private final static class BlindingParameters {
|
||||
private final static BigInteger BIG_TWO = BigInteger.valueOf(2L);
|
||||
|
||||
// RSA public exponent
|
||||
private final BigInteger e;
|
||||
|
||||
// hash code of RSA private exponent
|
||||
private final BigInteger d;
|
||||
|
||||
// r ^ e mod n (CRT), or r mod n (Non-CRT)
|
||||
private BigInteger u;
|
||||
|
||||
// r ^ (-1) mod n (CRT) , or ((r ^ (-1)) ^ d) mod n (Non-CRT)
|
||||
private BigInteger v;
|
||||
|
||||
// e: the public exponent
|
||||
// d: the private exponent
|
||||
// n: the modulus
|
||||
BlindingParameters(BigInteger e, BigInteger d, BigInteger n) {
|
||||
this.u = null;
|
||||
this.v = null;
|
||||
this.e = e;
|
||||
this.d = d;
|
||||
|
||||
int len = n.bitLength();
|
||||
SecureRandom random = JCAUtil.getSecureRandom();
|
||||
u = new BigInteger(len, random).mod(n);
|
||||
// Although the possibility is very much limited that u is zero
|
||||
// or is not relatively prime to n, we still want to be careful
|
||||
// about the special value.
|
||||
//
|
||||
// Secure random generation is expensive, try to use BigInteger.ONE
|
||||
// this time if this new generated random number is zero or is not
|
||||
// relatively prime to n. Next time, new generated secure random
|
||||
// number will be used instead.
|
||||
if (u.equals(BigInteger.ZERO)) {
|
||||
u = BigInteger.ONE; // use 1 this time
|
||||
}
|
||||
|
||||
try {
|
||||
// The call to BigInteger.modInverse() checks that u is
|
||||
// relatively prime to n. Otherwise, ArithmeticException is
|
||||
// thrown.
|
||||
v = u.modInverse(n);
|
||||
} catch (ArithmeticException ae) {
|
||||
// if u is not relatively prime to n, use 1 this time
|
||||
u = BigInteger.ONE;
|
||||
v = BigInteger.ONE;
|
||||
}
|
||||
|
||||
if (e != null) {
|
||||
u = u.modPow(e, n); // e: the public exponent
|
||||
// u: random ^ e
|
||||
// v: random ^ (-1)
|
||||
} else {
|
||||
v = v.modPow(d, n); // d: the private exponent
|
||||
// u: random
|
||||
// v: random ^ (-d)
|
||||
}
|
||||
}
|
||||
|
||||
// return null if need to reset the parameters
|
||||
BlindingRandomPair getBlindingRandomPair(
|
||||
BigInteger e, BigInteger d, BigInteger n) {
|
||||
|
||||
if ((this.e != null && this.e.equals(e)) ||
|
||||
(this.d != null && this.d.equals(d))) {
|
||||
|
||||
BlindingRandomPair brp = null;
|
||||
synchronized (this) {
|
||||
if (!u.equals(BigInteger.ZERO) &&
|
||||
!v.equals(BigInteger.ZERO)) {
|
||||
|
||||
brp = new BlindingRandomPair(u, v);
|
||||
if (u.compareTo(BigInteger.ONE) <= 0 ||
|
||||
v.compareTo(BigInteger.ONE) <= 0) {
|
||||
|
||||
// need to reset the random pair next time
|
||||
u = BigInteger.ZERO;
|
||||
v = BigInteger.ZERO;
|
||||
} else {
|
||||
u = u.modPow(BIG_TWO, n);
|
||||
v = v.modPow(BIG_TWO, n);
|
||||
}
|
||||
} // Otherwise, need to reset the random pair.
|
||||
}
|
||||
return brp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static BlindingRandomPair getBlindingRandomPair(
|
||||
BigInteger e, BigInteger d, BigInteger n) {
|
||||
|
||||
BlindingParameters bps = null;
|
||||
synchronized (blindingCache) {
|
||||
bps = blindingCache.get(n);
|
||||
}
|
||||
|
||||
if (bps == null) {
|
||||
bps = new BlindingParameters(e, d, n);
|
||||
synchronized (blindingCache) {
|
||||
blindingCache.putIfAbsent(n, bps);
|
||||
}
|
||||
}
|
||||
|
||||
BlindingRandomPair brp = bps.getBlindingRandomPair(e, d, n);
|
||||
if (brp == null) {
|
||||
// need to reset the blinding parameters
|
||||
bps = new BlindingParameters(e, d, n);
|
||||
synchronized (blindingCache) {
|
||||
blindingCache.replace(n, bps);
|
||||
}
|
||||
brp = bps.getBlindingRandomPair(e, d, n);
|
||||
}
|
||||
|
||||
return brp;
|
||||
}
|
||||
|
||||
}
|
||||
474
jdkSrc/jdk8/sun/security/rsa/RSAKeyFactory.java
Normal file
474
jdkSrc/jdk8/sun/security/rsa/RSAKeyFactory.java
Normal file
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import static sun.security.rsa.RSAUtil.KeyType;
|
||||
|
||||
/**
|
||||
* KeyFactory for RSA keys, e.g. "RSA", "RSASSA-PSS".
|
||||
* Keys must be instances of PublicKey or PrivateKey
|
||||
* and getAlgorithm() must return a value which matches the type which are
|
||||
* specified during construction time of the KeyFactory object.
|
||||
* For such keys, it supports conversion
|
||||
* between the following:
|
||||
*
|
||||
* For public keys:
|
||||
* . PublicKey with an X.509 encoding
|
||||
* . RSAPublicKey
|
||||
* . RSAPublicKeySpec
|
||||
* . X509EncodedKeySpec
|
||||
*
|
||||
* For private keys:
|
||||
* . PrivateKey with a PKCS#8 encoding
|
||||
* . RSAPrivateKey
|
||||
* . RSAPrivateCrtKey
|
||||
* . RSAPrivateKeySpec
|
||||
* . RSAPrivateCrtKeySpec
|
||||
* . PKCS8EncodedKeySpec
|
||||
* (of course, CRT variants only for CRT keys)
|
||||
*
|
||||
* Note: as always, RSA keys should be at least 512 bits long
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public class RSAKeyFactory extends KeyFactorySpi {
|
||||
|
||||
private static final Class<?> RSA_PUB_KEYSPEC_CLS = RSAPublicKeySpec.class;
|
||||
private static final Class<?> RSA_PRIV_KEYSPEC_CLS =
|
||||
RSAPrivateKeySpec.class;
|
||||
private static final Class<?> RSA_PRIVCRT_KEYSPEC_CLS =
|
||||
RSAPrivateCrtKeySpec.class;
|
||||
private static final Class<?> X509_KEYSPEC_CLS = X509EncodedKeySpec.class;
|
||||
private static final Class<?> PKCS8_KEYSPEC_CLS = PKCS8EncodedKeySpec.class;
|
||||
|
||||
public final static int MIN_MODLEN = 512;
|
||||
public final static int MAX_MODLEN = 16384;
|
||||
|
||||
private final KeyType type;
|
||||
|
||||
/*
|
||||
* If the modulus length is above this value, restrict the size of
|
||||
* the exponent to something that can be reasonably computed. We
|
||||
* could simply hardcode the exp len to something like 64 bits, but
|
||||
* this approach allows flexibility in case impls would like to use
|
||||
* larger module and exponent values.
|
||||
*/
|
||||
public final static int MAX_MODLEN_RESTRICT_EXP = 3072;
|
||||
public final static int MAX_RESTRICTED_EXPLEN = 64;
|
||||
|
||||
private static final boolean restrictExpLen =
|
||||
"true".equalsIgnoreCase(AccessController.doPrivileged(
|
||||
new GetPropertyAction(
|
||||
"sun.security.rsa.restrictRSAExponent", "true")));
|
||||
|
||||
static RSAKeyFactory getInstance(KeyType type) {
|
||||
return new RSAKeyFactory(type);
|
||||
}
|
||||
|
||||
// Internal utility method for checking key algorithm
|
||||
private static void checkKeyAlgo(Key key, String expectedAlg)
|
||||
throws InvalidKeyException {
|
||||
String keyAlg = key.getAlgorithm();
|
||||
if (keyAlg == null || !(keyAlg.equalsIgnoreCase(expectedAlg))) {
|
||||
throw new InvalidKeyException("Expected a " + expectedAlg
|
||||
+ " key, but got " + keyAlg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to convert Key into an instance of RSAPublicKeyImpl
|
||||
* or RSAPrivate(Crt)KeyImpl. If the key is not an RSA key or cannot be
|
||||
* used, throw an InvalidKeyException.
|
||||
*
|
||||
* Used by RSASignature and RSACipher.
|
||||
*/
|
||||
public static RSAKey toRSAKey(Key key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key must not be null");
|
||||
}
|
||||
if ((key instanceof RSAPrivateKeyImpl) ||
|
||||
(key instanceof RSAPrivateCrtKeyImpl) ||
|
||||
(key instanceof RSAPublicKeyImpl)) {
|
||||
return (RSAKey)key;
|
||||
} else {
|
||||
try {
|
||||
KeyType type = KeyType.lookup(key.getAlgorithm());
|
||||
RSAKeyFactory kf = RSAKeyFactory.getInstance(type);
|
||||
return (RSAKey) kf.engineTranslateKey(key);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Single test entry point for all of the mechanisms in the SunRsaSign
|
||||
* provider (RSA*KeyImpls). All of the tests are the same.
|
||||
*
|
||||
* For compatibility, we round up to the nearest byte here:
|
||||
* some Key impls might pass in a value within a byte of the
|
||||
* real value.
|
||||
*/
|
||||
static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)
|
||||
throws InvalidKeyException {
|
||||
checkKeyLengths(((modulusLen + 7) & ~7), exponent,
|
||||
RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the length of an RSA key modulus/exponent to make sure it
|
||||
* is not too short or long. Some impls have their own min and
|
||||
* max key sizes that may or may not match with a system defined value.
|
||||
*
|
||||
* @param modulusLen the bit length of the RSA modulus.
|
||||
* @param exponent the RSA exponent
|
||||
* @param minModulusLen if > 0, check to see if modulusLen is at
|
||||
* least this long, otherwise unused.
|
||||
* @param maxModulusLen caller will allow this max number of bits.
|
||||
* Allow the smaller of the system-defined maximum and this param.
|
||||
*
|
||||
* @throws InvalidKeyException if any of the values are unacceptable.
|
||||
*/
|
||||
public static void checkKeyLengths(int modulusLen, BigInteger exponent,
|
||||
int minModulusLen, int maxModulusLen) throws InvalidKeyException {
|
||||
|
||||
if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) {
|
||||
throw new InvalidKeyException( "RSA keys must be at least " +
|
||||
minModulusLen + " bits long");
|
||||
}
|
||||
|
||||
// Even though our policy file may allow this, we don't want
|
||||
// either value (mod/exp) to be too big.
|
||||
|
||||
int maxLen = Math.min(maxModulusLen, MAX_MODLEN);
|
||||
|
||||
// If a RSAPrivateKey/RSAPublicKey, make sure the
|
||||
// modulus len isn't too big.
|
||||
if (modulusLen > maxLen) {
|
||||
throw new InvalidKeyException(
|
||||
"RSA keys must be no longer than " + maxLen + " bits");
|
||||
}
|
||||
|
||||
// If a RSAPublicKey, make sure the exponent isn't too big.
|
||||
if (restrictExpLen && (exponent != null) &&
|
||||
(modulusLen > MAX_MODLEN_RESTRICT_EXP) &&
|
||||
(exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) {
|
||||
throw new InvalidKeyException(
|
||||
"RSA exponents can be no longer than " +
|
||||
MAX_RESTRICTED_EXPLEN + " bits " +
|
||||
" if modulus is greater than " +
|
||||
MAX_MODLEN_RESTRICT_EXP + " bits");
|
||||
}
|
||||
}
|
||||
|
||||
// disallowed as KeyType is required
|
||||
private RSAKeyFactory() {
|
||||
this.type = KeyType.RSA;
|
||||
}
|
||||
|
||||
public RSAKeyFactory(KeyType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an RSA key into a SunRsaSign RSA key. If conversion is
|
||||
* not possible, throw an InvalidKeyException.
|
||||
* See also JCA doc.
|
||||
*/
|
||||
protected Key engineTranslateKey(Key key) throws InvalidKeyException {
|
||||
if (key == null) {
|
||||
throw new InvalidKeyException("Key must not be null");
|
||||
}
|
||||
// ensure the key algorithm matches the current KeyFactory instance
|
||||
checkKeyAlgo(key, type.keyAlgo());
|
||||
|
||||
// no translation needed if the key is already our own impl
|
||||
if ((key instanceof RSAPrivateKeyImpl) ||
|
||||
(key instanceof RSAPrivateCrtKeyImpl) ||
|
||||
(key instanceof RSAPublicKeyImpl)) {
|
||||
return key;
|
||||
}
|
||||
if (key instanceof PublicKey) {
|
||||
return translatePublicKey((PublicKey)key);
|
||||
} else if (key instanceof PrivateKey) {
|
||||
return translatePrivateKey((PrivateKey)key);
|
||||
} else {
|
||||
throw new InvalidKeyException("Neither a public nor a private key");
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
protected PublicKey engineGeneratePublic(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
return generatePublic(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw e;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
return generatePrivate(keySpec);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw e;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of translateKey() for public keys. See JCA doc
|
||||
private PublicKey translatePublicKey(PublicKey key)
|
||||
throws InvalidKeyException {
|
||||
if (key instanceof RSAPublicKey) {
|
||||
RSAPublicKey rsaKey = (RSAPublicKey)key;
|
||||
try {
|
||||
return new RSAPublicKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaKey.getParams()),
|
||||
rsaKey.getModulus(),
|
||||
rsaKey.getPublicExponent());
|
||||
} catch (ProviderException e) {
|
||||
// catch providers that incorrectly implement RSAPublicKey
|
||||
throw new InvalidKeyException("Invalid key", e);
|
||||
}
|
||||
} else if ("X.509".equals(key.getFormat())) {
|
||||
RSAPublicKey translated = new RSAPublicKeyImpl(key.getEncoded());
|
||||
// ensure the key algorithm matches the current KeyFactory instance
|
||||
checkKeyAlgo(translated, type.keyAlgo());
|
||||
return translated;
|
||||
} else {
|
||||
throw new InvalidKeyException("Public keys must be instance "
|
||||
+ "of RSAPublicKey or have X.509 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of translateKey() for private keys. See JCA doc
|
||||
private PrivateKey translatePrivateKey(PrivateKey key)
|
||||
throws InvalidKeyException {
|
||||
if (key instanceof RSAPrivateCrtKey) {
|
||||
RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key;
|
||||
try {
|
||||
return new RSAPrivateCrtKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaKey.getParams()),
|
||||
rsaKey.getModulus(),
|
||||
rsaKey.getPublicExponent(),
|
||||
rsaKey.getPrivateExponent(),
|
||||
rsaKey.getPrimeP(),
|
||||
rsaKey.getPrimeQ(),
|
||||
rsaKey.getPrimeExponentP(),
|
||||
rsaKey.getPrimeExponentQ(),
|
||||
rsaKey.getCrtCoefficient()
|
||||
);
|
||||
} catch (ProviderException e) {
|
||||
// catch providers that incorrectly implement RSAPrivateCrtKey
|
||||
throw new InvalidKeyException("Invalid key", e);
|
||||
}
|
||||
} else if (key instanceof RSAPrivateKey) {
|
||||
RSAPrivateKey rsaKey = (RSAPrivateKey)key;
|
||||
try {
|
||||
return new RSAPrivateKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaKey.getParams()),
|
||||
rsaKey.getModulus(),
|
||||
rsaKey.getPrivateExponent()
|
||||
);
|
||||
} catch (ProviderException e) {
|
||||
// catch providers that incorrectly implement RSAPrivateKey
|
||||
throw new InvalidKeyException("Invalid key", e);
|
||||
}
|
||||
} else if ("PKCS#8".equals(key.getFormat())) {
|
||||
RSAPrivateKey translated =
|
||||
RSAPrivateCrtKeyImpl.newKey(key.getEncoded());
|
||||
// ensure the key algorithm matches the current KeyFactory instance
|
||||
checkKeyAlgo(translated, type.keyAlgo());
|
||||
return translated;
|
||||
} else {
|
||||
throw new InvalidKeyException("Private keys must be instance "
|
||||
+ "of RSAPrivate(Crt)Key or have PKCS#8 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of generatePublic. See JCA doc
|
||||
private PublicKey generatePublic(KeySpec keySpec)
|
||||
throws GeneralSecurityException {
|
||||
if (keySpec instanceof X509EncodedKeySpec) {
|
||||
X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
|
||||
RSAPublicKey generated = new RSAPublicKeyImpl(x509Spec.getEncoded());
|
||||
// ensure the key algorithm matches the current KeyFactory instance
|
||||
checkKeyAlgo(generated, type.keyAlgo());
|
||||
return generated;
|
||||
} else if (keySpec instanceof RSAPublicKeySpec) {
|
||||
RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec;
|
||||
try {
|
||||
return new RSAPublicKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),
|
||||
rsaSpec.getModulus(),
|
||||
rsaSpec.getPublicExponent()
|
||||
);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Only RSAPublicKeySpec "
|
||||
+ "and X509EncodedKeySpec supported for RSA public keys");
|
||||
}
|
||||
}
|
||||
|
||||
// internal implementation of generatePrivate. See JCA doc
|
||||
private PrivateKey generatePrivate(KeySpec keySpec)
|
||||
throws GeneralSecurityException {
|
||||
if (keySpec instanceof PKCS8EncodedKeySpec) {
|
||||
PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
|
||||
RSAPrivateKey generated = RSAPrivateCrtKeyImpl.newKey(pkcsSpec.getEncoded());
|
||||
// ensure the key algorithm matches the current KeyFactory instance
|
||||
checkKeyAlgo(generated, type.keyAlgo());
|
||||
return generated;
|
||||
} else if (keySpec instanceof RSAPrivateCrtKeySpec) {
|
||||
RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;
|
||||
try {
|
||||
return new RSAPrivateCrtKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),
|
||||
rsaSpec.getModulus(),
|
||||
rsaSpec.getPublicExponent(),
|
||||
rsaSpec.getPrivateExponent(),
|
||||
rsaSpec.getPrimeP(),
|
||||
rsaSpec.getPrimeQ(),
|
||||
rsaSpec.getPrimeExponentP(),
|
||||
rsaSpec.getPrimeExponentQ(),
|
||||
rsaSpec.getCrtCoefficient()
|
||||
);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
} else if (keySpec instanceof RSAPrivateKeySpec) {
|
||||
RSAPrivateKeySpec rsaSpec = (RSAPrivateKeySpec)keySpec;
|
||||
try {
|
||||
return new RSAPrivateKeyImpl(
|
||||
RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),
|
||||
rsaSpec.getModulus(),
|
||||
rsaSpec.getPrivateExponent()
|
||||
);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
|
||||
+ "and PKCS8EncodedKeySpec supported for RSA private keys");
|
||||
}
|
||||
}
|
||||
|
||||
protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
|
||||
throws InvalidKeySpecException {
|
||||
try {
|
||||
// convert key to one of our keys
|
||||
// this also verifies that the key is a valid RSA key and ensures
|
||||
// that the encoding is X.509/PKCS#8 for public/private keys
|
||||
key = engineTranslateKey(key);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidKeySpecException(e);
|
||||
}
|
||||
if (key instanceof RSAPublicKey) {
|
||||
RSAPublicKey rsaKey = (RSAPublicKey)key;
|
||||
if (keySpec.isAssignableFrom(RSA_PUB_KEYSPEC_CLS)) {
|
||||
return keySpec.cast(new RSAPublicKeySpec(
|
||||
rsaKey.getModulus(),
|
||||
rsaKey.getPublicExponent(),
|
||||
rsaKey.getParams()
|
||||
));
|
||||
} else if (keySpec.isAssignableFrom(X509_KEYSPEC_CLS)) {
|
||||
return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("KeySpec must be RSAPublicKeySpec or "
|
||||
+ "X509EncodedKeySpec for RSA public keys");
|
||||
}
|
||||
} else if (key instanceof RSAPrivateKey) {
|
||||
if (keySpec.isAssignableFrom(PKCS8_KEYSPEC_CLS)) {
|
||||
return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
|
||||
} else if (keySpec.isAssignableFrom(RSA_PRIVCRT_KEYSPEC_CLS)) {
|
||||
// All supported keyspecs (other than PKCS8_KEYSPEC_CLS) descend from RSA_PRIVCRT_KEYSPEC_CLS
|
||||
if (key instanceof RSAPrivateCrtKey) {
|
||||
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;
|
||||
return keySpec.cast(new RSAPrivateCrtKeySpec(
|
||||
crtKey.getModulus(),
|
||||
crtKey.getPublicExponent(),
|
||||
crtKey.getPrivateExponent(),
|
||||
crtKey.getPrimeP(),
|
||||
crtKey.getPrimeQ(),
|
||||
crtKey.getPrimeExponentP(),
|
||||
crtKey.getPrimeExponentQ(),
|
||||
crtKey.getCrtCoefficient(),
|
||||
crtKey.getParams()
|
||||
));
|
||||
} else { // RSAPrivateKey (non-CRT)
|
||||
if (!keySpec.isAssignableFrom(RSA_PRIV_KEYSPEC_CLS)) {
|
||||
throw new InvalidKeySpecException
|
||||
("RSAPrivateCrtKeySpec can only be used with CRT keys");
|
||||
}
|
||||
|
||||
// fall through to RSAPrivateKey (non-CRT)
|
||||
RSAPrivateKey rsaKey = (RSAPrivateKey) key;
|
||||
return keySpec.cast(new RSAPrivateKeySpec(
|
||||
rsaKey.getModulus(),
|
||||
rsaKey.getPrivateExponent(),
|
||||
rsaKey.getParams()
|
||||
));
|
||||
}
|
||||
} else {
|
||||
throw new InvalidKeySpecException
|
||||
("KeySpec must be RSAPrivate(Crt)KeySpec or "
|
||||
+ "PKCS8EncodedKeySpec for RSA private keys");
|
||||
}
|
||||
} else {
|
||||
// should not occur, caught in engineTranslateKey()
|
||||
throw new InvalidKeySpecException("Neither public nor private key");
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Legacy extends RSAKeyFactory {
|
||||
public Legacy() {
|
||||
super(KeyType.RSA);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PSS extends RSAKeyFactory {
|
||||
public PSS() {
|
||||
super(KeyType.PSS);
|
||||
}
|
||||
}
|
||||
}
|
||||
199
jdkSrc/jdk8/sun/security/rsa/RSAKeyPairGenerator.java
Normal file
199
jdkSrc/jdk8/sun/security/rsa/RSAKeyPairGenerator.java
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_RSA_KEY_SIZE;
|
||||
import static sun.security.util.SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import static sun.security.rsa.RSAUtil.KeyType;
|
||||
|
||||
/**
|
||||
* RSA keypair generation. Standard algorithm, minimum key length 512 bit.
|
||||
* We generate two random primes until we find two where phi is relative
|
||||
* prime to the public exponent. Default exponent is 65537. It has only bit 0
|
||||
* and bit 4 set, which makes it particularly efficient.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public abstract class RSAKeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
|
||||
// public exponent to use
|
||||
private BigInteger publicExponent;
|
||||
|
||||
// size of the key to generate, >= RSAKeyFactory.MIN_MODLEN
|
||||
private int keySize;
|
||||
|
||||
private final KeyType type;
|
||||
private AlgorithmId rsaId;
|
||||
|
||||
// PRNG to use
|
||||
private SecureRandom random;
|
||||
|
||||
RSAKeyPairGenerator(KeyType type, int defKeySize) {
|
||||
this.type = type;
|
||||
// initialize to default in case the app does not call initialize()
|
||||
initialize(defKeySize, null);
|
||||
}
|
||||
|
||||
// initialize the generator. See JCA doc
|
||||
public void initialize(int keySize, SecureRandom random) {
|
||||
try {
|
||||
initialize(new RSAKeyGenParameterSpec(keySize,
|
||||
RSAKeyGenParameterSpec.F4), random);
|
||||
} catch (InvalidAlgorithmParameterException iape) {
|
||||
throw new InvalidParameterException(iape.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// second initialize method. See JCA doc.
|
||||
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (params instanceof RSAKeyGenParameterSpec == false) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Params must be instance of RSAKeyGenParameterSpec");
|
||||
}
|
||||
|
||||
RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params;
|
||||
int tmpKeySize = rsaSpec.getKeysize();
|
||||
BigInteger tmpPublicExponent = rsaSpec.getPublicExponent();
|
||||
AlgorithmParameterSpec tmpParams = rsaSpec.getKeyParams();
|
||||
|
||||
if (tmpPublicExponent == null) {
|
||||
tmpPublicExponent = RSAKeyGenParameterSpec.F4;
|
||||
} else {
|
||||
if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Public exponent must be 3 or larger");
|
||||
}
|
||||
if (tmpPublicExponent.bitLength() > tmpKeySize) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Public exponent must be smaller than key size");
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow unreasonably large key sizes, probably user error
|
||||
try {
|
||||
RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent,
|
||||
512, 64 * 1024);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Invalid key sizes", e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.rsaId = RSAUtil.createAlgorithmId(type, tmpParams);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidAlgorithmParameterException(
|
||||
"Invalid key parameters", e);
|
||||
}
|
||||
|
||||
this.keySize = tmpKeySize;
|
||||
this.publicExponent = tmpPublicExponent;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
// generate the keypair. See JCA doc
|
||||
public KeyPair generateKeyPair() {
|
||||
// accommodate odd key sizes in case anybody wants to use them
|
||||
int lp = (keySize + 1) >> 1;
|
||||
int lq = keySize - lp;
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
BigInteger e = publicExponent;
|
||||
while (true) {
|
||||
// generate two random primes of size lp/lq
|
||||
BigInteger p = BigInteger.probablePrime(lp, random);
|
||||
BigInteger q, n;
|
||||
do {
|
||||
q = BigInteger.probablePrime(lq, random);
|
||||
// convention is for p > q
|
||||
if (p.compareTo(q) < 0) {
|
||||
BigInteger tmp = p;
|
||||
p = q;
|
||||
q = tmp;
|
||||
}
|
||||
// modulus n = p * q
|
||||
n = p.multiply(q);
|
||||
// even with correctly sized p and q, there is a chance that
|
||||
// n will be one bit short. re-generate the smaller prime if so
|
||||
} while (n.bitLength() < keySize);
|
||||
|
||||
// phi = (p - 1) * (q - 1) must be relative prime to e
|
||||
// otherwise RSA just won't work ;-)
|
||||
BigInteger p1 = p.subtract(BigInteger.ONE);
|
||||
BigInteger q1 = q.subtract(BigInteger.ONE);
|
||||
BigInteger phi = p1.multiply(q1);
|
||||
// generate new p and q until they work. typically
|
||||
// the first try will succeed when using F4
|
||||
if (e.gcd(phi).equals(BigInteger.ONE) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// private exponent d is the inverse of e mod phi
|
||||
BigInteger d = e.modInverse(phi);
|
||||
|
||||
// 1st prime exponent pe = d mod (p - 1)
|
||||
BigInteger pe = d.mod(p1);
|
||||
// 2nd prime exponent qe = d mod (q - 1)
|
||||
BigInteger qe = d.mod(q1);
|
||||
|
||||
// crt coefficient coeff is the inverse of q mod p
|
||||
BigInteger coeff = q.modInverse(p);
|
||||
|
||||
try {
|
||||
PublicKey publicKey = new RSAPublicKeyImpl(rsaId, n, e);
|
||||
PrivateKey privateKey = new RSAPrivateCrtKeyImpl(
|
||||
rsaId, n, e, d, p, q, pe, qe, coeff);
|
||||
return new KeyPair(publicKey, privateKey);
|
||||
} catch (InvalidKeyException exc) {
|
||||
// invalid key exception only thrown for keys < 512 bit,
|
||||
// will not happen here
|
||||
throw new RuntimeException(exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Legacy extends RSAKeyPairGenerator {
|
||||
public Legacy() {
|
||||
super(KeyType.RSA, DEF_RSA_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class PSS extends RSAKeyPairGenerator {
|
||||
public PSS() {
|
||||
super(KeyType.PSS, DEF_RSASSA_PSS_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
681
jdkSrc/jdk8/sun/security/rsa/RSAPSSSignature.java
Normal file
681
jdkSrc/jdk8/sun/security/rsa/RSAPSSSignature.java
Normal file
@@ -0,0 +1,681 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.spec.PSSParameterSpec;
|
||||
import java.security.spec.MGF1ParameterSpec;
|
||||
import java.security.interfaces.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import sun.security.util.*;
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
|
||||
/**
|
||||
* PKCS#1 v2.2 RSASSA-PSS signatures with various message digest algorithms.
|
||||
* RSASSA-PSS implementation takes the message digest algorithm, MGF algorithm,
|
||||
* and salt length values through the required signature PSS parameters.
|
||||
* We support SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, and
|
||||
* SHA-512/256 message digest algorithms and MGF1 mask generation function.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public class RSAPSSSignature extends SignatureSpi {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// utility method for comparing digest algorithms
|
||||
// NOTE that first argument is assumed to be standard digest name
|
||||
private boolean isDigestEqual(String stdAlg, String givenAlg) {
|
||||
if (stdAlg == null || givenAlg == null) return false;
|
||||
|
||||
if (givenAlg.indexOf("-") != -1) {
|
||||
return stdAlg.equalsIgnoreCase(givenAlg);
|
||||
} else {
|
||||
if (stdAlg.equals("SHA-1")) {
|
||||
return (givenAlg.equalsIgnoreCase("SHA")
|
||||
|| givenAlg.equalsIgnoreCase("SHA1"));
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder(givenAlg);
|
||||
// case-insensitive check
|
||||
if (givenAlg.regionMatches(true, 0, "SHA", 0, 3)) {
|
||||
givenAlg = sb.insert(3, "-").toString();
|
||||
return stdAlg.equalsIgnoreCase(givenAlg);
|
||||
} else {
|
||||
throw new ProviderException("Unsupported digest algorithm "
|
||||
+ givenAlg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] EIGHT_BYTES_OF_ZEROS = new byte[8];
|
||||
|
||||
private static final Hashtable<String, Integer> DIGEST_LENGTHS =
|
||||
new Hashtable<String, Integer>();
|
||||
static {
|
||||
DIGEST_LENGTHS.put("SHA-1", 20);
|
||||
DIGEST_LENGTHS.put("SHA", 20);
|
||||
DIGEST_LENGTHS.put("SHA1", 20);
|
||||
DIGEST_LENGTHS.put("SHA-224", 28);
|
||||
DIGEST_LENGTHS.put("SHA224", 28);
|
||||
DIGEST_LENGTHS.put("SHA-256", 32);
|
||||
DIGEST_LENGTHS.put("SHA256", 32);
|
||||
DIGEST_LENGTHS.put("SHA-384", 48);
|
||||
DIGEST_LENGTHS.put("SHA384", 48);
|
||||
DIGEST_LENGTHS.put("SHA-512", 64);
|
||||
DIGEST_LENGTHS.put("SHA512", 64);
|
||||
DIGEST_LENGTHS.put("SHA-512/224", 28);
|
||||
DIGEST_LENGTHS.put("SHA512/224", 28);
|
||||
DIGEST_LENGTHS.put("SHA-512/256", 32);
|
||||
DIGEST_LENGTHS.put("SHA512/256", 32);
|
||||
}
|
||||
|
||||
// message digest implementation we use for hashing the data
|
||||
private MessageDigest md;
|
||||
// flag indicating whether the digest is reset
|
||||
private boolean digestReset = true;
|
||||
|
||||
// private key, if initialized for signing
|
||||
private RSAPrivateKey privKey = null;
|
||||
// public key, if initialized for verifying
|
||||
private RSAPublicKey pubKey = null;
|
||||
// PSS parameters from signatures and keys respectively
|
||||
private PSSParameterSpec sigParams = null; // required for PSS signatures
|
||||
|
||||
// PRNG used to generate salt bytes if none given
|
||||
private SecureRandom random;
|
||||
|
||||
/**
|
||||
* Construct a new RSAPSSSignatur with arbitrary digest algorithm
|
||||
*/
|
||||
public RSAPSSSignature() {
|
||||
this.md = null;
|
||||
}
|
||||
|
||||
// initialize for verification. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey publicKey)
|
||||
throws InvalidKeyException {
|
||||
if (publicKey instanceof RSAPublicKey) {
|
||||
RSAPublicKey rsaPubKey = (RSAPublicKey)publicKey;
|
||||
isPublicKeyValid(rsaPubKey);
|
||||
this.pubKey = rsaPubKey;
|
||||
this.privKey = null;
|
||||
resetDigest();
|
||||
} else {
|
||||
throw new InvalidKeyException("key must be RSAPublicKey");
|
||||
}
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey)
|
||||
throws InvalidKeyException {
|
||||
engineInitSign(privateKey, null);
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
if (privateKey instanceof RSAPrivateKey) {
|
||||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)privateKey;
|
||||
isPrivateKeyValid(rsaPrivateKey);
|
||||
this.privKey = rsaPrivateKey;
|
||||
this.pubKey = null;
|
||||
this.random =
|
||||
(random == null ? JCAUtil.getSecureRandom() : random);
|
||||
resetDigest();
|
||||
} else {
|
||||
throw new InvalidKeyException("key must be RSAPrivateKey");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for checking the key PSS parameters against signature
|
||||
* PSS parameters.
|
||||
* Returns false if any of the digest/MGF algorithms and trailerField
|
||||
* values does not match or if the salt length in key parameters is
|
||||
* larger than the value in signature parameters.
|
||||
*/
|
||||
private static boolean isCompatible(AlgorithmParameterSpec keyParams,
|
||||
PSSParameterSpec sigParams) {
|
||||
if (keyParams == null) {
|
||||
// key with null PSS parameters means no restriction
|
||||
return true;
|
||||
}
|
||||
if (!(keyParams instanceof PSSParameterSpec)) {
|
||||
return false;
|
||||
}
|
||||
// nothing to compare yet, defer the check to when sigParams is set
|
||||
if (sigParams == null) {
|
||||
return true;
|
||||
}
|
||||
PSSParameterSpec pssKeyParams = (PSSParameterSpec) keyParams;
|
||||
// first check the salt length requirement
|
||||
if (pssKeyParams.getSaltLength() > sigParams.getSaltLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compare equality of the rest of fields based on DER encoding
|
||||
PSSParameterSpec keyParams2 =
|
||||
new PSSParameterSpec(pssKeyParams.getDigestAlgorithm(),
|
||||
pssKeyParams.getMGFAlgorithm(),
|
||||
pssKeyParams.getMGFParameters(),
|
||||
sigParams.getSaltLength(),
|
||||
pssKeyParams.getTrailerField());
|
||||
PSSParameters ap = new PSSParameters();
|
||||
// skip the JCA overhead
|
||||
try {
|
||||
ap.engineInit(keyParams2);
|
||||
byte[] encoded = ap.engineGetEncoded();
|
||||
ap.engineInit(sigParams);
|
||||
byte[] encoded2 = ap.engineGetEncoded();
|
||||
return Arrays.equals(encoded, encoded2);
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified RSAPrivateKey
|
||||
*/
|
||||
private void isPrivateKeyValid(RSAPrivateKey prKey) throws InvalidKeyException {
|
||||
try {
|
||||
if (prKey instanceof RSAPrivateCrtKey) {
|
||||
RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)prKey;
|
||||
if (RSAPrivateCrtKeyImpl.checkComponents(crtKey)) {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(
|
||||
crtKey.getModulus().bitLength(),
|
||||
crtKey.getPublicExponent());
|
||||
} else {
|
||||
throw new InvalidKeyException(
|
||||
"Some of the CRT-specific components are not available");
|
||||
}
|
||||
} else {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(
|
||||
prKey.getModulus().bitLength(),
|
||||
null);
|
||||
}
|
||||
} catch (InvalidKeyException ikEx) {
|
||||
throw ikEx;
|
||||
} catch (Exception e) {
|
||||
throw new InvalidKeyException(
|
||||
"Can not access private key components", e);
|
||||
}
|
||||
isValid(prKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified RSAPublicKey
|
||||
*/
|
||||
private void isPublicKeyValid(RSAPublicKey pKey) throws InvalidKeyException {
|
||||
try {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(
|
||||
pKey.getModulus().bitLength(),
|
||||
pKey.getPublicExponent());
|
||||
} catch (InvalidKeyException ikEx) {
|
||||
throw ikEx;
|
||||
} catch (Exception e) {
|
||||
throw new InvalidKeyException(
|
||||
"Can not access public key components", e);
|
||||
}
|
||||
isValid(pKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified RSAKey and its associated parameters against
|
||||
* internal signature parameters.
|
||||
*/
|
||||
private void isValid(RSAKey rsaKey) throws InvalidKeyException {
|
||||
try {
|
||||
AlgorithmParameterSpec keyParams = rsaKey.getParams();
|
||||
// validate key parameters
|
||||
if (!isCompatible(rsaKey.getParams(), this.sigParams)) {
|
||||
throw new InvalidKeyException
|
||||
("Key contains incompatible PSS parameter values");
|
||||
}
|
||||
// validate key length
|
||||
if (this.sigParams != null) {
|
||||
Integer hLen =
|
||||
DIGEST_LENGTHS.get(this.sigParams.getDigestAlgorithm());
|
||||
if (hLen == null) {
|
||||
throw new ProviderException("Unsupported digest algo: " +
|
||||
this.sigParams.getDigestAlgorithm());
|
||||
}
|
||||
checkKeyLength(rsaKey, hLen, this.sigParams.getSaltLength());
|
||||
}
|
||||
} catch (SignatureException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the specified Signature PSS parameters.
|
||||
*/
|
||||
private PSSParameterSpec validateSigParams(AlgorithmParameterSpec p)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (p == null) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Parameters cannot be null");
|
||||
}
|
||||
if (!(p instanceof PSSParameterSpec)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("parameters must be type PSSParameterSpec");
|
||||
}
|
||||
// no need to validate again if same as current signature parameters
|
||||
PSSParameterSpec params = (PSSParameterSpec) p;
|
||||
if (params == this.sigParams) return params;
|
||||
|
||||
RSAKey key = (this.privKey == null? this.pubKey : this.privKey);
|
||||
// check against keyParams if set
|
||||
if (key != null) {
|
||||
if (!isCompatible(key.getParams(), params)) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Signature parameters does not match key parameters");
|
||||
}
|
||||
}
|
||||
// now sanity check the parameter values
|
||||
if (!(params.getMGFAlgorithm().equalsIgnoreCase("MGF1"))) {
|
||||
throw new InvalidAlgorithmParameterException("Only supports MGF1");
|
||||
|
||||
}
|
||||
if (params.getTrailerField() != PSSParameterSpec.TRAILER_FIELD_BC) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Only supports TrailerFieldBC(1)");
|
||||
|
||||
}
|
||||
String digestAlgo = params.getDigestAlgorithm();
|
||||
// check key length again
|
||||
if (key != null) {
|
||||
try {
|
||||
int hLen = DIGEST_LENGTHS.get(digestAlgo);
|
||||
checkKeyLength(key, hLen, params.getSaltLength());
|
||||
} catch (SignatureException e) {
|
||||
throw new InvalidAlgorithmParameterException(e);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the object is initialized with key and parameters and
|
||||
* reset digest
|
||||
*/
|
||||
private void ensureInit() throws SignatureException {
|
||||
RSAKey key = (this.privKey == null? this.pubKey : this.privKey);
|
||||
if (key == null) {
|
||||
throw new SignatureException("Missing key");
|
||||
}
|
||||
if (this.sigParams == null) {
|
||||
// Parameters are required for signature verification
|
||||
throw new SignatureException
|
||||
("Parameters required for RSASSA-PSS signatures");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for checking key length against digest length and
|
||||
* salt length
|
||||
*/
|
||||
private static void checkKeyLength(RSAKey key, int digestLen,
|
||||
int saltLen) throws SignatureException {
|
||||
if (key != null) {
|
||||
int keyLength = (getKeyLengthInBits(key) + 7) >> 3;
|
||||
int minLength = Math.addExact(Math.addExact(digestLen, saltLen), 2);
|
||||
if (keyLength < minLength) {
|
||||
throw new SignatureException
|
||||
("Key is too short, need min " + minLength + " bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the message digest if it is not already reset.
|
||||
*/
|
||||
private void resetDigest() {
|
||||
if (digestReset == false) {
|
||||
this.md.reset();
|
||||
digestReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message digest value.
|
||||
*/
|
||||
private byte[] getDigestValue() {
|
||||
digestReset = true;
|
||||
return this.md.digest();
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
ensureInit();
|
||||
this.md.update(b);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
ensureInit();
|
||||
this.md.update(b, off, len);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer b) {
|
||||
try {
|
||||
ensureInit();
|
||||
} catch (SignatureException se) {
|
||||
// hack for working around API bug
|
||||
throw new RuntimeException(se.getMessage());
|
||||
}
|
||||
this.md.update(b);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// sign the data and return the signature. See JCA doc
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
ensureInit();
|
||||
byte[] mHash = getDigestValue();
|
||||
try {
|
||||
byte[] encoded = encodeSignature(mHash);
|
||||
byte[] encrypted = RSACore.rsa(encoded, privKey, true);
|
||||
return encrypted;
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignatureException("Could not sign data", e);
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("Could not encode data", e);
|
||||
}
|
||||
}
|
||||
|
||||
// verify the data and return the result. See JCA doc
|
||||
// should be reset to the state after engineInitVerify call.
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||
ensureInit();
|
||||
try {
|
||||
if (sigBytes.length != RSACore.getByteLength(this.pubKey)) {
|
||||
throw new SignatureException
|
||||
("Signature length not correct: got "
|
||||
+ sigBytes.length + " but was expecting "
|
||||
+ RSACore.getByteLength(this.pubKey));
|
||||
}
|
||||
byte[] mHash = getDigestValue();
|
||||
byte[] decrypted = RSACore.rsa(sigBytes, this.pubKey);
|
||||
return decodeSignature(mHash, decrypted);
|
||||
} catch (javax.crypto.BadPaddingException e) {
|
||||
// occurs if the app has used the wrong RSA public key
|
||||
// or if sigBytes is invalid
|
||||
// return false rather than propagating the exception for
|
||||
// compatibility/ease of use
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("Signature encoding error", e);
|
||||
} finally {
|
||||
resetDigest();
|
||||
}
|
||||
}
|
||||
|
||||
// return the modulus length in bits
|
||||
private static int getKeyLengthInBits(RSAKey k) {
|
||||
if (k != null) {
|
||||
return k.getModulus().bitLength();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the digest 'mHash', return the to-be-signed data.
|
||||
* Also used by the PKCS#11 provider.
|
||||
*/
|
||||
private byte[] encodeSignature(byte[] mHash)
|
||||
throws IOException, DigestException {
|
||||
AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters();
|
||||
String mgfDigestAlgo;
|
||||
if (mgfParams != null) {
|
||||
mgfDigestAlgo =
|
||||
((MGF1ParameterSpec) mgfParams).getDigestAlgorithm();
|
||||
} else {
|
||||
mgfDigestAlgo = this.md.getAlgorithm();
|
||||
}
|
||||
try {
|
||||
int emBits = getKeyLengthInBits(this.privKey) - 1;
|
||||
int emLen = (emBits + 7) >> 3;
|
||||
int hLen = this.md.getDigestLength();
|
||||
int dbLen = emLen - hLen - 1;
|
||||
int sLen = this.sigParams.getSaltLength();
|
||||
|
||||
// maps DB into the corresponding region of EM and
|
||||
// stores its bytes directly into EM
|
||||
byte[] em = new byte[emLen];
|
||||
|
||||
// step7 and some of step8
|
||||
em[dbLen - sLen - 1] = (byte) 1; // set DB's padding2 into EM
|
||||
em[em.length - 1] = (byte) 0xBC; // set trailer field of EM
|
||||
|
||||
if (!digestReset) {
|
||||
throw new ProviderException("Digest should be reset");
|
||||
}
|
||||
// step5: generates M' using padding1, mHash, and salt
|
||||
this.md.update(EIGHT_BYTES_OF_ZEROS);
|
||||
digestReset = false; // mark digest as it now has data
|
||||
this.md.update(mHash);
|
||||
if (sLen != 0) {
|
||||
// step4: generate random salt
|
||||
byte[] salt = new byte[sLen];
|
||||
this.random.nextBytes(salt);
|
||||
this.md.update(salt);
|
||||
|
||||
// step8: set DB's salt into EM
|
||||
System.arraycopy(salt, 0, em, dbLen - sLen, sLen);
|
||||
}
|
||||
// step6: generate H using M'
|
||||
this.md.digest(em, dbLen, hLen); // set H field of EM
|
||||
digestReset = true;
|
||||
|
||||
// step7 and 8 are already covered by the code which setting up
|
||||
// EM as above
|
||||
|
||||
// step9 and 10: feed H into MGF and xor with DB in EM
|
||||
MGF1 mgf1 = new MGF1(mgfDigestAlgo);
|
||||
mgf1.generateAndXor(em, dbLen, hLen, dbLen, em, 0);
|
||||
|
||||
// step11: set the leftmost (8emLen - emBits) bits of the leftmost
|
||||
// octet to 0
|
||||
int numZeroBits = (emLen << 3) - emBits;
|
||||
|
||||
if (numZeroBits != 0) {
|
||||
byte MASK = (byte) (0xff >>> numZeroBits);
|
||||
em[0] = (byte) (em[0] & MASK);
|
||||
}
|
||||
|
||||
// step12: em should now holds maskedDB || hash h || 0xBC
|
||||
return em;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IOException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the signature data as under RFC8017 sec9.1.2 EMSA-PSS-VERIFY
|
||||
*/
|
||||
private boolean decodeSignature(byte[] mHash, byte[] em)
|
||||
throws IOException {
|
||||
int hLen = mHash.length;
|
||||
int sLen = this.sigParams.getSaltLength();
|
||||
int emBits = getKeyLengthInBits(this.pubKey) - 1;
|
||||
int emLen = (emBits + 7) >> 3;
|
||||
|
||||
// When key length is 8N+1 bits (N+1 bytes), emBits = 8N,
|
||||
// emLen = N which is one byte shorter than em.length.
|
||||
// Otherwise, emLen should be same as em.length
|
||||
int emOfs = em.length - emLen;
|
||||
if ((emOfs == 1) && (em[0] != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// step3
|
||||
if (emLen < (hLen + sLen + 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// step4
|
||||
if (em[emOfs + emLen - 1] != (byte) 0xBC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// step6: check if the leftmost (8emLen - emBits) bits of the leftmost
|
||||
// octet are 0
|
||||
int numZeroBits = (emLen << 3) - emBits;
|
||||
|
||||
if (numZeroBits != 0) {
|
||||
byte MASK = (byte) (0xff << (8 - numZeroBits));
|
||||
if ((em[emOfs] & MASK) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String mgfDigestAlgo;
|
||||
AlgorithmParameterSpec mgfParams = this.sigParams.getMGFParameters();
|
||||
if (mgfParams != null) {
|
||||
mgfDigestAlgo =
|
||||
((MGF1ParameterSpec) mgfParams).getDigestAlgorithm();
|
||||
} else {
|
||||
mgfDigestAlgo = this.md.getAlgorithm();
|
||||
}
|
||||
// step 7 and 8
|
||||
int dbLen = emLen - hLen - 1;
|
||||
try {
|
||||
MGF1 mgf1 = new MGF1(mgfDigestAlgo);
|
||||
mgf1.generateAndXor(em, emOfs + dbLen, hLen, dbLen,
|
||||
em, emOfs);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new IOException(nsae.toString());
|
||||
}
|
||||
|
||||
// step9: set the leftmost (8emLen - emBits) bits of the leftmost
|
||||
// octet to 0
|
||||
if (numZeroBits != 0) {
|
||||
byte MASK = (byte) (0xff >>> numZeroBits);
|
||||
em[emOfs] = (byte) (em[emOfs] & MASK);
|
||||
}
|
||||
|
||||
// step10
|
||||
int i = emOfs;
|
||||
for (; i < emOfs + (dbLen - sLen - 1); i++) {
|
||||
if (em[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (em[i] != 0x01) {
|
||||
return false;
|
||||
}
|
||||
// step12 and 13
|
||||
this.md.update(EIGHT_BYTES_OF_ZEROS);
|
||||
digestReset = false;
|
||||
this.md.update(mHash);
|
||||
if (sLen > 0) {
|
||||
this.md.update(em, emOfs + (dbLen - sLen), sLen);
|
||||
}
|
||||
byte[] digest2 = this.md.digest();
|
||||
digestReset = true;
|
||||
|
||||
// step14
|
||||
byte[] digestInEM = Arrays.copyOfRange(em, emOfs + dbLen,
|
||||
emOfs + emLen - 1);
|
||||
return MessageDigest.isEqual(digest2, digestInEM);
|
||||
}
|
||||
|
||||
// set parameter, not supported. See JCA doc
|
||||
@Deprecated
|
||||
@Override
|
||||
protected void engineSetParameter(String param, Object value)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("setParameter() not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
this.sigParams = validateSigParams(params);
|
||||
// disallow changing parameters when digest has been used
|
||||
if (!digestReset) {
|
||||
throw new ProviderException
|
||||
("Cannot set parameters during operations");
|
||||
}
|
||||
String newHashAlg = this.sigParams.getDigestAlgorithm();
|
||||
// re-allocate md if not yet assigned or algorithm changed
|
||||
if ((this.md == null) ||
|
||||
!(this.md.getAlgorithm().equalsIgnoreCase(newHashAlg))) {
|
||||
try {
|
||||
this.md = MessageDigest.getInstance(newHashAlg);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
// should not happen as we pick default digest algorithm
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Unsupported digest algorithm " +
|
||||
newHashAlg, nsae);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get parameter, not supported. See JCA doc
|
||||
@Deprecated
|
||||
@Override
|
||||
protected Object engineGetParameter(String param)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("getParameter() not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
AlgorithmParameters ap = null;
|
||||
if (this.sigParams != null) {
|
||||
try {
|
||||
ap = AlgorithmParameters.getInstance("RSASSA-PSS");
|
||||
ap.init(this.sigParams);
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new ProviderException(gse.getMessage());
|
||||
}
|
||||
}
|
||||
return ap;
|
||||
}
|
||||
}
|
||||
542
jdkSrc/jdk8/sun/security/rsa/RSAPadding.java
Normal file
542
jdkSrc/jdk8/sun/security/rsa/RSAPadding.java
Normal file
@@ -0,0 +1,542 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
|
||||
import javax.crypto.spec.PSource;
|
||||
import javax.crypto.spec.OAEPParameterSpec;
|
||||
|
||||
import sun.security.jca.JCAUtil;
|
||||
|
||||
/**
|
||||
* RSA padding and unpadding.
|
||||
*
|
||||
* The various PKCS#1 versions can be found in the IETF RFCs
|
||||
* tracking the corresponding PKCS#1 standards.
|
||||
*
|
||||
* RFC 2313: PKCS#1 v1.5
|
||||
* RFC 2437: PKCS#1 v2.0
|
||||
* RFC 3447: PKCS#1 v2.1
|
||||
* RFC 8017: PKCS#1 v2.2
|
||||
*
|
||||
* The format of PKCS#1 v1.5 padding is:
|
||||
*
|
||||
* 0x00 | BT | PS...PS | 0x00 | data...data
|
||||
*
|
||||
* where BT is the blocktype (1 or 2). The length of the entire string
|
||||
* must be the same as the size of the modulus (i.e. 128 byte for a 1024 bit
|
||||
* key). Per spec, the padding string must be at least 8 bytes long. That
|
||||
* leaves up to (length of key in bytes) - 11 bytes for the data.
|
||||
*
|
||||
* OAEP padding was introduced in PKCS#1 v2.0 and is a bit more complicated
|
||||
* and has a number of options. We support:
|
||||
*
|
||||
* . arbitrary hash functions ('Hash' in the specification), MessageDigest
|
||||
* implementation must be available
|
||||
* . MGF1 as the mask generation function
|
||||
* . the empty string as the default value for label L and whatever
|
||||
* specified in javax.crypto.spec.OAEPParameterSpec
|
||||
*
|
||||
* The algorithms (representations) are forwards-compatible: that is,
|
||||
* the algorithm described in previous releases are in later releases.
|
||||
* However, additional comments/checks/clarifications were added to the
|
||||
* later versions based on real-world experience (e.g. stricter v1.5
|
||||
* format checking.)
|
||||
*
|
||||
* Note: RSA keys should be at least 512 bits long
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class RSAPadding {
|
||||
|
||||
// NOTE: the constants below are embedded in the JCE RSACipher class
|
||||
// file. Do not change without coordinating the update
|
||||
|
||||
// PKCS#1 v1.5 padding, blocktype 1 (signing)
|
||||
public final static int PAD_BLOCKTYPE_1 = 1;
|
||||
// PKCS#1 v1.5 padding, blocktype 2 (encryption)
|
||||
public final static int PAD_BLOCKTYPE_2 = 2;
|
||||
// nopadding. Does not do anything, but allows simpler RSACipher code
|
||||
public final static int PAD_NONE = 3;
|
||||
// PKCS#1 v2.1 OAEP padding
|
||||
public final static int PAD_OAEP_MGF1 = 4;
|
||||
|
||||
// type, one of PAD_*
|
||||
private final int type;
|
||||
|
||||
// size of the padded block (i.e. size of the modulus)
|
||||
private final int paddedSize;
|
||||
|
||||
// PRNG used to generate padding bytes (PAD_BLOCKTYPE_2, PAD_OAEP_MGF1)
|
||||
private SecureRandom random;
|
||||
|
||||
// maximum size of the data
|
||||
private final int maxDataSize;
|
||||
|
||||
// OAEP: main message digest
|
||||
private MessageDigest md;
|
||||
|
||||
// OAEP: MGF1
|
||||
private MGF1 mgf;
|
||||
|
||||
// OAEP: value of digest of data (user-supplied or zero-length) using md
|
||||
private byte[] lHash;
|
||||
|
||||
/**
|
||||
* Get a RSAPadding instance of the specified type.
|
||||
* Keys used with this padding must be paddedSize bytes long.
|
||||
*/
|
||||
public static RSAPadding getInstance(int type, int paddedSize)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
return new RSAPadding(type, paddedSize, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a RSAPadding instance of the specified type.
|
||||
* Keys used with this padding must be paddedSize bytes long.
|
||||
*/
|
||||
public static RSAPadding getInstance(int type, int paddedSize,
|
||||
SecureRandom random) throws InvalidKeyException,
|
||||
InvalidAlgorithmParameterException {
|
||||
return new RSAPadding(type, paddedSize, random, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a RSAPadding instance of the specified type, which must be
|
||||
* OAEP. Keys used with this padding must be paddedSize bytes long.
|
||||
*/
|
||||
public static RSAPadding getInstance(int type, int paddedSize,
|
||||
SecureRandom random, OAEPParameterSpec spec)
|
||||
throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
return new RSAPadding(type, paddedSize, random, spec);
|
||||
}
|
||||
|
||||
// internal constructor
|
||||
private RSAPadding(int type, int paddedSize, SecureRandom random,
|
||||
OAEPParameterSpec spec) throws InvalidKeyException,
|
||||
InvalidAlgorithmParameterException {
|
||||
this.type = type;
|
||||
this.paddedSize = paddedSize;
|
||||
this.random = random;
|
||||
if (paddedSize < 64) {
|
||||
// sanity check, already verified in RSASignature/RSACipher
|
||||
throw new InvalidKeyException("Padded size must be at least 64");
|
||||
}
|
||||
switch (type) {
|
||||
case PAD_BLOCKTYPE_1:
|
||||
case PAD_BLOCKTYPE_2:
|
||||
maxDataSize = paddedSize - 11;
|
||||
break;
|
||||
case PAD_NONE:
|
||||
maxDataSize = paddedSize;
|
||||
break;
|
||||
case PAD_OAEP_MGF1:
|
||||
String mdName = "SHA-1";
|
||||
String mgfMdName = mdName;
|
||||
byte[] digestInput = null;
|
||||
try {
|
||||
if (spec != null) {
|
||||
mdName = spec.getDigestAlgorithm();
|
||||
String mgfName = spec.getMGFAlgorithm();
|
||||
if (!mgfName.equalsIgnoreCase("MGF1")) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Unsupported MGF algo: " + mgfName);
|
||||
}
|
||||
mgfMdName = ((MGF1ParameterSpec)spec.getMGFParameters())
|
||||
.getDigestAlgorithm();
|
||||
PSource pSrc = spec.getPSource();
|
||||
String pSrcAlgo = pSrc.getAlgorithm();
|
||||
if (!pSrcAlgo.equalsIgnoreCase("PSpecified")) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Unsupported pSource algo: " + pSrcAlgo);
|
||||
}
|
||||
digestInput = ((PSource.PSpecified) pSrc).getValue();
|
||||
}
|
||||
md = MessageDigest.getInstance(mdName);
|
||||
mgf = new MGF1(mgfMdName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new InvalidKeyException("Digest not available", e);
|
||||
}
|
||||
lHash = getInitialHash(md, digestInput);
|
||||
int digestLen = lHash.length;
|
||||
maxDataSize = paddedSize - 2 - 2 * digestLen;
|
||||
if (maxDataSize <= 0) {
|
||||
throw new InvalidKeyException
|
||||
("Key is too short for encryption using OAEPPadding" +
|
||||
" with " + mdName + " and " + mgf.getName());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidKeyException("Invalid padding: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
// cache of hashes of zero length data
|
||||
private static final Map<String,byte[]> emptyHashes =
|
||||
Collections.synchronizedMap(new HashMap<String,byte[]>());
|
||||
|
||||
/**
|
||||
* Return the value of the digest using the specified message digest
|
||||
* <code>md</code> and the digest input <code>digestInput</code>.
|
||||
* if <code>digestInput</code> is null or 0-length, zero length
|
||||
* is used to generate the initial digest.
|
||||
* Note: the md object must be in reset state
|
||||
*/
|
||||
private static byte[] getInitialHash(MessageDigest md,
|
||||
byte[] digestInput) {
|
||||
byte[] result;
|
||||
if ((digestInput == null) || (digestInput.length == 0)) {
|
||||
String digestName = md.getAlgorithm();
|
||||
result = emptyHashes.get(digestName);
|
||||
if (result == null) {
|
||||
result = md.digest();
|
||||
emptyHashes.put(digestName, result);
|
||||
}
|
||||
} else {
|
||||
result = md.digest(digestInput);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size of the plaintext data that can be processed
|
||||
* using this object.
|
||||
*/
|
||||
public int getMaxDataSize() {
|
||||
return maxDataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad the data and return the result or null if error occurred.
|
||||
*/
|
||||
public byte[] pad(byte[] data) {
|
||||
return pad(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad the data and return the result or null if error occurred.
|
||||
*/
|
||||
public byte[] pad(byte[] data, int ofs, int len) {
|
||||
if (len > maxDataSize) {
|
||||
return null;
|
||||
}
|
||||
switch (type) {
|
||||
case PAD_NONE:
|
||||
// assert len == paddedSize and data.length - ofs > len?
|
||||
return RSACore.convert(data, ofs, len);
|
||||
case PAD_BLOCKTYPE_1:
|
||||
case PAD_BLOCKTYPE_2:
|
||||
return padV15(data, ofs, len);
|
||||
case PAD_OAEP_MGF1:
|
||||
return padOAEP(data, ofs, len);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpad the padded block and return the result or null if error occurred.
|
||||
*/
|
||||
public byte[] unpad(byte[] padded) {
|
||||
if (padded.length == paddedSize) {
|
||||
switch (type) {
|
||||
case PAD_NONE:
|
||||
return padded;
|
||||
case PAD_BLOCKTYPE_1:
|
||||
case PAD_BLOCKTYPE_2:
|
||||
return unpadV15(padded);
|
||||
case PAD_OAEP_MGF1:
|
||||
return unpadOAEP(padded);
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 v1.5 padding (blocktype 1 and 2).
|
||||
*/
|
||||
private byte[] padV15(byte[] data, int ofs, int len) {
|
||||
byte[] padded = new byte[paddedSize];
|
||||
System.arraycopy(data, ofs, padded, paddedSize - len, len);
|
||||
int psSize = paddedSize - 3 - len;
|
||||
int k = 0;
|
||||
padded[k++] = 0;
|
||||
padded[k++] = (byte)type;
|
||||
if (type == PAD_BLOCKTYPE_1) {
|
||||
// blocktype 1: all padding bytes are 0xff
|
||||
while (psSize-- > 0) {
|
||||
padded[k++] = (byte)0xff;
|
||||
}
|
||||
} else {
|
||||
// blocktype 2: padding bytes are random non-zero bytes
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
// generate non-zero padding bytes
|
||||
// use a buffer to reduce calls to SecureRandom
|
||||
byte[] r = new byte[64];
|
||||
int i = -1;
|
||||
while (psSize-- > 0) {
|
||||
int b;
|
||||
do {
|
||||
if (i < 0) {
|
||||
random.nextBytes(r);
|
||||
i = r.length - 1;
|
||||
}
|
||||
b = r[i--] & 0xff;
|
||||
} while (b == 0);
|
||||
padded[k++] = (byte)b;
|
||||
}
|
||||
}
|
||||
return padded;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)).
|
||||
* Return the result or null if error occurred.
|
||||
* Note that we want to make it a constant-time operation
|
||||
*/
|
||||
private byte[] unpadV15(byte[] padded) {
|
||||
int paddedLength = padded.length;
|
||||
|
||||
if (paddedLength < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The following check ensures that the lead byte is zero and
|
||||
// the second byte is equivalent to the padding type. The
|
||||
// bp (bad padding) variable throughout this unpadding process will
|
||||
// be updated and remain 0 if good padding, 1 if bad.
|
||||
int p0 = padded[0];
|
||||
int p1 = padded[1];
|
||||
int bp = (-(p0 & 0xff) | ((p1 - type) | (type - p1))) >>> 31;
|
||||
|
||||
int padLen = 0;
|
||||
int k = 2;
|
||||
// Walk through the random, nonzero padding bytes. For each padding
|
||||
// byte bp and padLen will remain zero. When the end-of-padding
|
||||
// byte (0x00) is reached then padLen will be set to the index of the
|
||||
// first byte of the message content.
|
||||
while (k < paddedLength) {
|
||||
int b = padded[k++] & 0xff;
|
||||
padLen += (k * (1 - ((-(b | padLen)) >>> 31)));
|
||||
if (k == paddedLength) {
|
||||
bp = bp | (1 - ((-padLen) >>> 31));
|
||||
}
|
||||
bp = bp | (1 - (-(((type - PAD_BLOCKTYPE_1) & 0xff) |
|
||||
padLen | (1 - ((b - 0xff) >>> 31))) >>> 31));
|
||||
}
|
||||
int n = paddedLength - padLen;
|
||||
// So long as n <= maxDataSize, bp will remain zero
|
||||
bp = bp | ((maxDataSize - n) >>> 31);
|
||||
|
||||
// copy useless padding array for a constant-time method
|
||||
byte[] padding = new byte[padLen + 2];
|
||||
for (int i = 0; i < padLen; i++) {
|
||||
padding[i] = padded[i];
|
||||
}
|
||||
|
||||
byte[] data = new byte[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
data[i] = padded[padLen + i];
|
||||
}
|
||||
|
||||
if ((bp | padding[bp]) != 0) {
|
||||
// using the array padding here hoping that this way
|
||||
// the compiler does not eliminate the above useless copy
|
||||
return null;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] unpadForTls(byte[] padded, int clientVersion,
|
||||
int serverVersion) {
|
||||
int paddedLength = padded.length;
|
||||
|
||||
// bp is positive if the padding is bad and 0 if it is good so far
|
||||
int bp = (((int) padded[0] | ((int)padded[1] - PAD_BLOCKTYPE_2)) &
|
||||
0xFFF);
|
||||
|
||||
int k = 2;
|
||||
while (k < paddedLength - 49) {
|
||||
int b = padded[k++] & 0xFF;
|
||||
bp = bp | (1 - (-b >>> 31)); // if (padded[k] == 0) bp |= 1;
|
||||
}
|
||||
bp |= ((int)padded[k++] & 0xFF);
|
||||
int encodedVersion = ((padded[k] & 0xFF) << 8) | (padded[k + 1] & 0xFF);
|
||||
|
||||
int bv1 = clientVersion - encodedVersion;
|
||||
bv1 |= -bv1;
|
||||
int bv3 = serverVersion - encodedVersion;
|
||||
bv3 |= -bv3;
|
||||
int bv2 = (0x301 - clientVersion);
|
||||
|
||||
bp |= ((bv1 & (bv2 | bv3)) >>> 28);
|
||||
|
||||
byte[] data = Arrays.copyOfRange(padded, paddedLength - 48,
|
||||
paddedLength);
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
|
||||
byte[] fake = new byte[48];
|
||||
random.nextBytes(fake);
|
||||
|
||||
bp = (-bp >> 24);
|
||||
|
||||
// Now bp is 0 if the padding and version number were good and
|
||||
// -1 otherwise.
|
||||
for (int i = 0; i < 48; i++) {
|
||||
data[i] = (byte)((~bp & data[i]) | (bp & fake[i]));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 v2.0 OAEP padding (MGF1).
|
||||
* Paragraph references refer to PKCS#1 v2.1 (June 14, 2002)
|
||||
* Return the result or null if error occurred.
|
||||
*/
|
||||
private byte[] padOAEP(byte[] M, int ofs, int len) {
|
||||
if (random == null) {
|
||||
random = JCAUtil.getSecureRandom();
|
||||
}
|
||||
int hLen = lHash.length;
|
||||
|
||||
// 2.d: generate a random octet string seed of length hLen
|
||||
// if necessary
|
||||
byte[] seed = new byte[hLen];
|
||||
random.nextBytes(seed);
|
||||
|
||||
// buffer for encoded message EM
|
||||
byte[] EM = new byte[paddedSize];
|
||||
|
||||
// start and length of seed (as index into EM)
|
||||
int seedStart = 1;
|
||||
int seedLen = hLen;
|
||||
|
||||
// copy seed into EM
|
||||
System.arraycopy(seed, 0, EM, seedStart, seedLen);
|
||||
|
||||
// start and length of data block DB in EM
|
||||
// we place it inside of EM to reduce copying
|
||||
int dbStart = hLen + 1;
|
||||
int dbLen = EM.length - dbStart;
|
||||
|
||||
// start of message M in EM
|
||||
int mStart = paddedSize - len;
|
||||
|
||||
// build DB
|
||||
// 2.b: Concatenate lHash, PS, a single octet with hexadecimal value
|
||||
// 0x01, and the message M to form a data block DB of length
|
||||
// k - hLen -1 octets as DB = lHash || PS || 0x01 || M
|
||||
// (note that PS is all zeros)
|
||||
System.arraycopy(lHash, 0, EM, dbStart, hLen);
|
||||
EM[mStart - 1] = 1;
|
||||
System.arraycopy(M, ofs, EM, mStart, len);
|
||||
|
||||
// produce maskedDB
|
||||
mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
|
||||
|
||||
// produce maskSeed
|
||||
mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
|
||||
|
||||
return EM;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#1 v2.1 OAEP unpadding (MGF1).
|
||||
* Return the result or null if error occurred.
|
||||
*/
|
||||
private byte[] unpadOAEP(byte[] padded) {
|
||||
byte[] EM = padded;
|
||||
boolean bp = false;
|
||||
int hLen = lHash.length;
|
||||
|
||||
if (EM[0] != 0) {
|
||||
bp = true;
|
||||
}
|
||||
|
||||
int seedStart = 1;
|
||||
int seedLen = hLen;
|
||||
|
||||
int dbStart = hLen + 1;
|
||||
int dbLen = EM.length - dbStart;
|
||||
|
||||
mgf.generateAndXor(EM, dbStart, dbLen, seedLen, EM, seedStart);
|
||||
mgf.generateAndXor(EM, seedStart, seedLen, dbLen, EM, dbStart);
|
||||
|
||||
// verify lHash == lHash'
|
||||
for (int i = 0; i < hLen; i++) {
|
||||
if (lHash[i] != EM[dbStart + i]) {
|
||||
bp = true;
|
||||
}
|
||||
}
|
||||
|
||||
int padStart = dbStart + hLen;
|
||||
int onePos = -1;
|
||||
|
||||
for (int i = padStart; i < EM.length; i++) {
|
||||
int value = EM[i];
|
||||
if (onePos == -1) {
|
||||
if (value == 0x00) {
|
||||
// continue;
|
||||
} else if (value == 0x01) {
|
||||
onePos = i;
|
||||
} else { // Anything other than {0,1} is bad.
|
||||
bp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We either ran off the rails or found something other than 0/1.
|
||||
if (onePos == -1) {
|
||||
bp = true;
|
||||
onePos = EM.length - 1; // Don't inadvertently return any data.
|
||||
}
|
||||
|
||||
int mStart = onePos + 1;
|
||||
|
||||
// copy useless padding array for a constant-time method
|
||||
byte [] tmp = new byte[mStart - padStart];
|
||||
System.arraycopy(EM, padStart, tmp, 0, tmp.length);
|
||||
|
||||
byte [] m = new byte[EM.length - mStart];
|
||||
System.arraycopy(EM, mStart, m, 0, m.length);
|
||||
|
||||
return (bp? null : m);
|
||||
}
|
||||
}
|
||||
303
jdkSrc/jdk8/sun/security/rsa/RSAPrivateCrtKeyImpl.java
Normal file
303
jdkSrc/jdk8/sun/security/rsa/RSAPrivateCrtKeyImpl.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
import java.security.interfaces.*;
|
||||
|
||||
import sun.security.util.*;
|
||||
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
|
||||
import static sun.security.rsa.RSAUtil.KeyType;
|
||||
|
||||
/**
|
||||
* RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in CRT form.
|
||||
* For non-CRT private keys, see RSAPrivateKeyImpl. We need separate classes
|
||||
* to ensure correct behavior in instanceof checks, etc.
|
||||
* <p>
|
||||
* Note: RSA keys must be at least 512 bits long
|
||||
*
|
||||
* @see RSAPrivateKeyImpl
|
||||
* @see RSAKeyFactory
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class RSAPrivateCrtKeyImpl
|
||||
extends PKCS8Key implements RSAPrivateCrtKey {
|
||||
|
||||
private static final long serialVersionUID = -1326088454257084918L;
|
||||
|
||||
private BigInteger n; // modulus
|
||||
private BigInteger e; // public exponent
|
||||
private BigInteger d; // private exponent
|
||||
private BigInteger p; // prime p
|
||||
private BigInteger q; // prime q
|
||||
private BigInteger pe; // prime exponent p
|
||||
private BigInteger qe; // prime exponent q
|
||||
private BigInteger coeff; // CRT coeffcient
|
||||
|
||||
// Optional parameters associated with this RSA key
|
||||
// specified in the encoding of its AlgorithmId.
|
||||
// Must be null for "RSA" keys.
|
||||
private AlgorithmParameterSpec keyParams;
|
||||
|
||||
/**
|
||||
* Generate a new key from its encoding. Returns a CRT key if possible
|
||||
* and a non-CRT key otherwise. Used by RSAKeyFactory.
|
||||
*/
|
||||
public static RSAPrivateKey newKey(byte[] encoded)
|
||||
throws InvalidKeyException {
|
||||
RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded);
|
||||
// check all CRT-specific components are available, if any one
|
||||
// missing, return a non-CRT key instead
|
||||
if (checkComponents(key)) {
|
||||
return key;
|
||||
} else {
|
||||
return new RSAPrivateKeyImpl(
|
||||
key.algid,
|
||||
key.getModulus(),
|
||||
key.getPrivateExponent());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate if all CRT-specific components are available.
|
||||
*/
|
||||
static boolean checkComponents(RSAPrivateCrtKey key) {
|
||||
return !((key.getPublicExponent().signum() == 0) ||
|
||||
(key.getPrimeExponentP().signum() == 0) ||
|
||||
(key.getPrimeExponentQ().signum() == 0) ||
|
||||
(key.getPrimeP().signum() == 0) ||
|
||||
(key.getPrimeQ().signum() == 0) ||
|
||||
(key.getCrtCoefficient().signum() == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new key from the specified type and components.
|
||||
* Returns a CRT key if possible and a non-CRT key otherwise.
|
||||
* Used by SunPKCS11 provider.
|
||||
*/
|
||||
public static RSAPrivateKey newKey(KeyType type,
|
||||
AlgorithmParameterSpec params,
|
||||
BigInteger n, BigInteger e, BigInteger d,
|
||||
BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,
|
||||
BigInteger coeff) throws InvalidKeyException {
|
||||
RSAPrivateKey key;
|
||||
AlgorithmId rsaId = RSAUtil.createAlgorithmId(type, params);
|
||||
if ((e.signum() == 0) || (p.signum() == 0) ||
|
||||
(q.signum() == 0) || (pe.signum() == 0) ||
|
||||
(qe.signum() == 0) || (coeff.signum() == 0)) {
|
||||
// if any component is missing, return a non-CRT key
|
||||
return new RSAPrivateKeyImpl(rsaId, n, d);
|
||||
} else {
|
||||
return new RSAPrivateCrtKeyImpl(rsaId, n, e, d,
|
||||
p, q, pe, qe, coeff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a key from its encoding. Called from newKey above.
|
||||
*/
|
||||
RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||
if (encoded == null || encoded.length == 0) {
|
||||
throw new InvalidKeyException("Missing key encoding");
|
||||
}
|
||||
|
||||
decode(encoded);
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
|
||||
try {
|
||||
// this will check the validity of params
|
||||
this.keyParams = RSAUtil.getParamSpec(algid);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a RSA key from its components. Used by the
|
||||
* RSAKeyFactory and the RSAKeyPairGenerator.
|
||||
*/
|
||||
RSAPrivateCrtKeyImpl(AlgorithmId rsaId,
|
||||
BigInteger n, BigInteger e, BigInteger d,
|
||||
BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,
|
||||
BigInteger coeff) throws InvalidKeyException {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
|
||||
|
||||
this.n = n;
|
||||
this.e = e;
|
||||
this.d = d;
|
||||
this.p = p;
|
||||
this.q = q;
|
||||
this.pe = pe;
|
||||
this.qe = qe;
|
||||
this.coeff = coeff;
|
||||
this.keyParams = RSAUtil.getParamSpec(rsaId);
|
||||
|
||||
// generate the encoding
|
||||
algid = rsaId;
|
||||
try {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(0); // version must be 0
|
||||
out.putInteger(n);
|
||||
out.putInteger(e);
|
||||
out.putInteger(d);
|
||||
out.putInteger(p);
|
||||
out.putInteger(q);
|
||||
out.putInteger(pe);
|
||||
out.putInteger(qe);
|
||||
out.putInteger(coeff);
|
||||
DerValue val =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
key = val.toByteArray();
|
||||
} catch (IOException exc) {
|
||||
// should never occur
|
||||
throw new InvalidKeyException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return algid.getName();
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getModulus() {
|
||||
return n;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPublicExponent() {
|
||||
return e;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrivateExponent() {
|
||||
return d;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrimeP() {
|
||||
return p;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrimeQ() {
|
||||
return q;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrimeExponentP() {
|
||||
return pe;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrimeExponentQ() {
|
||||
return qe;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getCrtCoefficient() {
|
||||
return coeff;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public AlgorithmParameterSpec getParams() {
|
||||
return keyParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the key. Called by PKCS8Key.
|
||||
*/
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
try {
|
||||
DerInputStream in = new DerInputStream(key);
|
||||
DerValue derValue = in.getDerValue();
|
||||
if (derValue.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Not a SEQUENCE");
|
||||
}
|
||||
DerInputStream data = derValue.data;
|
||||
int version = data.getInteger();
|
||||
if (version != 0) {
|
||||
throw new IOException("Version must be 0");
|
||||
}
|
||||
|
||||
/*
|
||||
* Some implementations do not correctly encode ASN.1 INTEGER values
|
||||
* in 2's complement format, resulting in a negative integer when
|
||||
* decoded. Correct the error by converting it to a positive integer.
|
||||
*
|
||||
* See CR 6255949
|
||||
*/
|
||||
n = data.getPositiveBigInteger();
|
||||
e = data.getPositiveBigInteger();
|
||||
d = data.getPositiveBigInteger();
|
||||
p = data.getPositiveBigInteger();
|
||||
q = data.getPositiveBigInteger();
|
||||
pe = data.getPositiveBigInteger();
|
||||
qe = data.getPositiveBigInteger();
|
||||
coeff = data.getPositiveBigInteger();
|
||||
if (derValue.data.available() != 0) {
|
||||
throw new IOException("Extra data available");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid RSA private key", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"RSAPrivateCrtKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
140
jdkSrc/jdk8/sun/security/rsa/RSAPrivateKeyImpl.java
Normal file
140
jdkSrc/jdk8/sun/security/rsa/RSAPrivateKeyImpl.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.interfaces.*;
|
||||
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
|
||||
/**
|
||||
* RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in non-CRT
|
||||
* form (modulus, private exponent only).
|
||||
* <p>
|
||||
* For CRT private keys, see RSAPrivateCrtKeyImpl. We need separate classes
|
||||
* to ensure correct behavior in instanceof checks, etc.
|
||||
* <p>
|
||||
* Note: RSA keys must be at least 512 bits long
|
||||
*
|
||||
* @see RSAPrivateCrtKeyImpl
|
||||
* @see RSAKeyFactory
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class RSAPrivateKeyImpl extends PKCS8Key implements RSAPrivateKey {
|
||||
|
||||
private static final long serialVersionUID = -33106691987952810L;
|
||||
|
||||
private final BigInteger n; // modulus
|
||||
private final BigInteger d; // private exponent
|
||||
|
||||
// optional parameters associated with this RSA key
|
||||
// specified in the encoding of its AlgorithmId.
|
||||
// must be null for "RSA" keys.
|
||||
private final AlgorithmParameterSpec keyParams;
|
||||
|
||||
/**
|
||||
* Construct a key from its components. Used by the
|
||||
* RSAKeyFactory and the RSAKeyPairGenerator.
|
||||
*/
|
||||
RSAPrivateKeyImpl(AlgorithmId rsaId, BigInteger n, BigInteger d)
|
||||
throws InvalidKeyException {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), null);
|
||||
|
||||
this.n = n;
|
||||
this.d = d;
|
||||
this.keyParams = RSAUtil.getParamSpec(rsaId);
|
||||
|
||||
// generate the encoding
|
||||
algid = rsaId;
|
||||
try {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(0); // version must be 0
|
||||
out.putInteger(n);
|
||||
out.putInteger(0);
|
||||
out.putInteger(d);
|
||||
out.putInteger(0);
|
||||
out.putInteger(0);
|
||||
out.putInteger(0);
|
||||
out.putInteger(0);
|
||||
out.putInteger(0);
|
||||
DerValue val =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
key = val.toByteArray();
|
||||
} catch (IOException exc) {
|
||||
// should never occur
|
||||
throw new InvalidKeyException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return algid.getName();
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getModulus() {
|
||||
return n;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPrivateExponent() {
|
||||
return d;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public AlgorithmParameterSpec getParams() {
|
||||
return keyParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"RSAPrivateKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
224
jdkSrc/jdk8/sun/security/rsa/RSAPublicKeyImpl.java
Normal file
224
jdkSrc/jdk8/sun/security/rsa/RSAPublicKeyImpl.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
import java.security.interfaces.*;
|
||||
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.X509Key;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
|
||||
import static sun.security.rsa.RSAUtil.KeyType;
|
||||
|
||||
/**
|
||||
* RSA public key implementation for "RSA", "RSASSA-PSS" algorithms.
|
||||
* <p>
|
||||
* Note: RSA keys must be at least 512 bits long
|
||||
*
|
||||
* @see RSAPrivateCrtKeyImpl
|
||||
* @see RSAPrivateKeyImpl
|
||||
* @see RSAKeyFactory
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class RSAPublicKeyImpl extends X509Key implements RSAPublicKey {
|
||||
|
||||
private static final long serialVersionUID = 2644735423591199609L;
|
||||
private static final BigInteger THREE = BigInteger.valueOf(3);
|
||||
|
||||
private BigInteger n; // modulus
|
||||
private BigInteger e; // public exponent
|
||||
|
||||
// optional parameters associated with this RSA key
|
||||
// specified in the encoding of its AlgorithmId
|
||||
// must be null for "RSA" keys.
|
||||
private AlgorithmParameterSpec keyParams;
|
||||
|
||||
/**
|
||||
* Generate a new RSAPublicKey from the specified encoding.
|
||||
* Used by SunPKCS11 provider.
|
||||
*/
|
||||
public static RSAPublicKey newKey(byte[] encoded)
|
||||
throws InvalidKeyException {
|
||||
return new RSAPublicKeyImpl(encoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new RSAPublicKey from the specified type and components.
|
||||
* Used by SunPKCS11 provider.
|
||||
*/
|
||||
public static RSAPublicKey newKey(KeyType type,
|
||||
AlgorithmParameterSpec params, BigInteger n, BigInteger e)
|
||||
throws InvalidKeyException {
|
||||
AlgorithmId rsaId = RSAUtil.createAlgorithmId(type, params);
|
||||
return new RSAPublicKeyImpl(rsaId, n, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a RSA key from AlgorithmId and its components. Used by
|
||||
* RSAKeyFactory and RSAKeyPairGenerator.
|
||||
*/
|
||||
RSAPublicKeyImpl(AlgorithmId rsaId, BigInteger n, BigInteger e)
|
||||
throws InvalidKeyException {
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
|
||||
checkExponentRange(n, e);
|
||||
|
||||
this.n = n;
|
||||
this.e = e;
|
||||
this.keyParams = RSAUtil.getParamSpec(rsaId);
|
||||
|
||||
// generate the encoding
|
||||
algid = rsaId;
|
||||
try {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.putInteger(n);
|
||||
out.putInteger(e);
|
||||
byte[] keyArray =
|
||||
new DerValue(DerValue.tag_Sequence,
|
||||
out.toByteArray()).toByteArray();
|
||||
setKey(new BitArray(keyArray.length*8, keyArray));
|
||||
} catch (IOException exc) {
|
||||
// should never occur
|
||||
throw new InvalidKeyException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a key from its encoding. Used by RSAKeyFactory.
|
||||
*/
|
||||
RSAPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
|
||||
if (encoded == null || encoded.length == 0) {
|
||||
throw new InvalidKeyException("Missing key encoding");
|
||||
}
|
||||
decode(encoded); // this sets n and e value
|
||||
RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
|
||||
checkExponentRange(n, e);
|
||||
|
||||
try {
|
||||
// this will check the validity of params
|
||||
this.keyParams = RSAUtil.getParamSpec(algid);
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeyException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// pkg private utility method for checking RSA modulus and public exponent
|
||||
static void checkExponentRange(BigInteger mod, BigInteger exp)
|
||||
throws InvalidKeyException {
|
||||
// the exponent should be smaller than the modulus
|
||||
if (exp.compareTo(mod) >= 0) {
|
||||
throw new InvalidKeyException("exponent is larger than modulus");
|
||||
}
|
||||
|
||||
// the exponent should be at least 3
|
||||
if (exp.compareTo(THREE) < 0) {
|
||||
throw new InvalidKeyException("exponent is smaller than 3");
|
||||
}
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public String getAlgorithm() {
|
||||
return algid.getName();
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getModulus() {
|
||||
return n;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public BigInteger getPublicExponent() {
|
||||
return e;
|
||||
}
|
||||
|
||||
// see JCA doc
|
||||
@Override
|
||||
public AlgorithmParameterSpec getParams() {
|
||||
return keyParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the key. Called by X509Key.
|
||||
*/
|
||||
protected void parseKeyBits() throws InvalidKeyException {
|
||||
try {
|
||||
DerInputStream in = new DerInputStream(getKey().toByteArray());
|
||||
DerValue derValue = in.getDerValue();
|
||||
if (derValue.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("Not a SEQUENCE");
|
||||
}
|
||||
DerInputStream data = derValue.data;
|
||||
n = data.getPositiveBigInteger();
|
||||
e = data.getPositiveBigInteger();
|
||||
if (derValue.data.available() != 0) {
|
||||
throw new IOException("Extra data available");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidKeyException("Invalid RSA public key", e);
|
||||
}
|
||||
}
|
||||
|
||||
// return a string representation of this key for debugging
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sun " + getAlgorithm() + " public key, " + n.bitLength()
|
||||
+ " bits" + "\n params: " + keyParams + "\n modulus: " + n
|
||||
+ "\n public exponent: " + e;
|
||||
}
|
||||
|
||||
private Object writeReplace() throws java.io.ObjectStreamException {
|
||||
return new KeyRep(KeyRep.Type.PUBLIC,
|
||||
getAlgorithm(),
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the state of this object from the stream.
|
||||
* <p>
|
||||
* Deserialization of this object is not supported.
|
||||
*
|
||||
* @param stream the {@code ObjectInputStream} from which data is read
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws ClassNotFoundException if a serialized class cannot be loaded
|
||||
*/
|
||||
private void readObject(ObjectInputStream stream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException(
|
||||
"RSAPublicKeyImpl keys are not directly deserializable");
|
||||
}
|
||||
}
|
||||
364
jdkSrc/jdk8/sun/security/rsa/RSASignature.java
Normal file
364
jdkSrc/jdk8/sun/security/rsa/RSASignature.java
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.security.*;
|
||||
import java.security.interfaces.*;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import sun.security.rsa.RSAUtil.KeyType;
|
||||
import sun.security.util.*;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
|
||||
/**
|
||||
* PKCS#1 v1.5 RSA signatures with the various message digest algorithms.
|
||||
* This file contains an abstract base class with all the logic plus
|
||||
* a nested static class for each of the message digest algorithms
|
||||
* (see end of the file). We support MD2, MD5, SHA-1, SHA-224, SHA-256,
|
||||
* SHA-384, SHA-512, SHA-512/224, and SHA-512/256.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public abstract class RSASignature extends SignatureSpi {
|
||||
|
||||
// we sign an ASN.1 SEQUENCE of AlgorithmId and digest
|
||||
// it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest]
|
||||
// this means the encoded length is (8 + digestOID.length + digest.length)
|
||||
private static final int baseLength = 8;
|
||||
|
||||
// object identifier for the message digest algorithm used
|
||||
private final ObjectIdentifier digestOID;
|
||||
|
||||
// length of the encoded signature blob
|
||||
private final int encodedLength;
|
||||
|
||||
// message digest implementation we use
|
||||
private final MessageDigest md;
|
||||
// flag indicating whether the digest is reset
|
||||
private boolean digestReset;
|
||||
|
||||
// private key, if initialized for signing
|
||||
private RSAPrivateKey privateKey;
|
||||
// public key, if initialized for verifying
|
||||
private RSAPublicKey publicKey;
|
||||
|
||||
// padding to use, set when the initSign/initVerify is called
|
||||
private RSAPadding padding;
|
||||
|
||||
/**
|
||||
* Construct a new RSASignature. Used by subclasses.
|
||||
*/
|
||||
RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) {
|
||||
this.digestOID = digestOID;
|
||||
try {
|
||||
md = MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
digestReset = true;
|
||||
encodedLength = baseLength + oidLength + md.getDigestLength();
|
||||
}
|
||||
|
||||
// initialize for verification. See JCA doc
|
||||
@Override
|
||||
protected void engineInitVerify(PublicKey publicKey)
|
||||
throws InvalidKeyException {
|
||||
RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey);
|
||||
this.privateKey = null;
|
||||
this.publicKey = rsaKey;
|
||||
initCommon(rsaKey, null);
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey)
|
||||
throws InvalidKeyException {
|
||||
engineInitSign(privateKey, null);
|
||||
}
|
||||
|
||||
// initialize for signing. See JCA doc
|
||||
@Override
|
||||
protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
RSAPrivateKey rsaKey =
|
||||
(RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
|
||||
this.privateKey = rsaKey;
|
||||
this.publicKey = null;
|
||||
initCommon(rsaKey, random);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init code common to sign and verify.
|
||||
*/
|
||||
private void initCommon(RSAKey rsaKey, SecureRandom random)
|
||||
throws InvalidKeyException {
|
||||
try {
|
||||
RSAUtil.checkParamsAgainstType(KeyType.RSA, rsaKey.getParams());
|
||||
} catch (ProviderException e) {
|
||||
throw new InvalidKeyException("Invalid key for RSA signatures", e);
|
||||
}
|
||||
resetDigest();
|
||||
int keySize = RSACore.getByteLength(rsaKey);
|
||||
try {
|
||||
padding = RSAPadding.getInstance
|
||||
(RSAPadding.PAD_BLOCKTYPE_1, keySize, random);
|
||||
} catch (InvalidAlgorithmParameterException iape) {
|
||||
throw new InvalidKeyException(iape.getMessage());
|
||||
}
|
||||
int maxDataSize = padding.getMaxDataSize();
|
||||
if (encodedLength > maxDataSize) {
|
||||
throw new InvalidKeyException
|
||||
("Key is too short for this signature algorithm");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the message digest if it is not already reset.
|
||||
*/
|
||||
private void resetDigest() {
|
||||
if (digestReset == false) {
|
||||
md.reset();
|
||||
digestReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message digest value.
|
||||
*/
|
||||
private byte[] getDigestValue() {
|
||||
digestReset = true;
|
||||
return md.digest();
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte b) throws SignatureException {
|
||||
md.update(b);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(byte[] b, int off, int len)
|
||||
throws SignatureException {
|
||||
md.update(b, off, len);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// update the signature with the plaintext data. See JCA doc
|
||||
@Override
|
||||
protected void engineUpdate(ByteBuffer b) {
|
||||
md.update(b);
|
||||
digestReset = false;
|
||||
}
|
||||
|
||||
// sign the data and return the signature. See JCA doc
|
||||
@Override
|
||||
protected byte[] engineSign() throws SignatureException {
|
||||
if (privateKey == null) {
|
||||
throw new SignatureException("Missing private key");
|
||||
}
|
||||
byte[] digest = getDigestValue();
|
||||
try {
|
||||
byte[] encoded = encodeSignature(digestOID, digest);
|
||||
byte[] padded = padding.pad(encoded);
|
||||
if (padded != null) {
|
||||
return RSACore.rsa(padded, privateKey, true);
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignatureException("Could not sign data", e);
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("Could not encode data", e);
|
||||
}
|
||||
throw new SignatureException("Could not sign data");
|
||||
}
|
||||
|
||||
// verify the data and return the result. See JCA doc
|
||||
@Override
|
||||
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
|
||||
if (publicKey == null) {
|
||||
throw new SignatureException("Missing public key");
|
||||
}
|
||||
|
||||
if (sigBytes.length != RSACore.getByteLength(publicKey)) {
|
||||
throw new SignatureException("Bad signature length: got " +
|
||||
sigBytes.length + " but was expecting " +
|
||||
RSACore.getByteLength(publicKey));
|
||||
}
|
||||
|
||||
try {
|
||||
// https://www.rfc-editor.org/rfc/rfc8017.html#section-8.2.2
|
||||
// Step 4 suggests comparing the encoded message
|
||||
byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
|
||||
|
||||
byte[] digest = getDigestValue();
|
||||
|
||||
byte[] encoded = encodeSignature(digestOID, digest);
|
||||
byte[] padded = padding.pad(encoded);
|
||||
if (MessageDigest.isEqual(padded, decrypted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Some vendors might omit the NULL params in digest algorithm
|
||||
// identifier. Try again.
|
||||
encoded = encodeSignatureWithoutNULL(digestOID, digest);
|
||||
padded = padding.pad(encoded);
|
||||
return MessageDigest.isEqual(padded, decrypted);
|
||||
} catch (javax.crypto.BadPaddingException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
throw new SignatureException("Signature encoding error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the digest, return the to-be-signed data.
|
||||
* Also used by the PKCS#11 provider.
|
||||
*/
|
||||
public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest)
|
||||
throws IOException {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
new AlgorithmId(oid).encode(out);
|
||||
out.putOctetString(digest);
|
||||
DerValue result =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the digest without the NULL params, return the to-be-signed data.
|
||||
* This is only used by SunRsaSign.
|
||||
*/
|
||||
static byte[] encodeSignatureWithoutNULL(ObjectIdentifier oid, byte[] digest)
|
||||
throws IOException {
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
DerOutputStream oidout = new DerOutputStream();
|
||||
oidout.putOID(oid);
|
||||
out.write(DerValue.tag_Sequence, oidout);
|
||||
out.putOctetString(digest);
|
||||
DerValue result =
|
||||
new DerValue(DerValue.tag_Sequence, out.toByteArray());
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
// set parameter, not supported. See JCA doc
|
||||
@Deprecated
|
||||
@Override
|
||||
protected void engineSetParameter(String param, Object value)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("setParameter() not supported");
|
||||
}
|
||||
|
||||
// See JCA doc
|
||||
@Override
|
||||
protected void engineSetParameter(AlgorithmParameterSpec params)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
if (params != null) {
|
||||
throw new InvalidAlgorithmParameterException("No parameters accepted");
|
||||
}
|
||||
}
|
||||
|
||||
// get parameter, not supported. See JCA doc
|
||||
@Deprecated
|
||||
@Override
|
||||
protected Object engineGetParameter(String param)
|
||||
throws InvalidParameterException {
|
||||
throw new UnsupportedOperationException("getParameter() not supported");
|
||||
}
|
||||
|
||||
// See JCA doc
|
||||
@Override
|
||||
protected AlgorithmParameters engineGetParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Nested class for MD2withRSA signatures
|
||||
public static final class MD2withRSA extends RSASignature {
|
||||
public MD2withRSA() {
|
||||
super("MD2", AlgorithmId.MD2_oid, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for MD5withRSA signatures
|
||||
public static final class MD5withRSA extends RSASignature {
|
||||
public MD5withRSA() {
|
||||
super("MD5", AlgorithmId.MD5_oid, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA1withRSA signatures
|
||||
public static final class SHA1withRSA extends RSASignature {
|
||||
public SHA1withRSA() {
|
||||
super("SHA-1", AlgorithmId.SHA_oid, 7);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA224withRSA signatures
|
||||
public static final class SHA224withRSA extends RSASignature {
|
||||
public SHA224withRSA() {
|
||||
super("SHA-224", AlgorithmId.SHA224_oid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA256withRSA signatures
|
||||
public static final class SHA256withRSA extends RSASignature {
|
||||
public SHA256withRSA() {
|
||||
super("SHA-256", AlgorithmId.SHA256_oid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA384withRSA signatures
|
||||
public static final class SHA384withRSA extends RSASignature {
|
||||
public SHA384withRSA() {
|
||||
super("SHA-384", AlgorithmId.SHA384_oid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA512withRSA signatures
|
||||
public static final class SHA512withRSA extends RSASignature {
|
||||
public SHA512withRSA() {
|
||||
super("SHA-512", AlgorithmId.SHA512_oid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA512/224withRSA signatures
|
||||
public static final class SHA512_224withRSA extends RSASignature {
|
||||
public SHA512_224withRSA() {
|
||||
super("SHA-512/224", AlgorithmId.SHA512_224_oid, 11);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class for SHA512/256withRSA signatures
|
||||
public static final class SHA512_256withRSA extends RSASignature {
|
||||
public SHA512_256withRSA() {
|
||||
super("SHA-512/256", AlgorithmId.SHA512_256_oid, 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
162
jdkSrc/jdk8/sun/security/rsa/RSAUtil.java
Normal file
162
jdkSrc/jdk8/sun/security/rsa/RSAUtil.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.security.spec.*;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
|
||||
/**
|
||||
* Utility class for SunRsaSign provider.
|
||||
* Currently used by RSAKeyPairGenerator and RSAKeyFactory.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public class RSAUtil {
|
||||
|
||||
public enum KeyType {
|
||||
RSA ("RSA"),
|
||||
PSS ("RSASSA-PSS")
|
||||
;
|
||||
|
||||
private final String algo;
|
||||
|
||||
KeyType(String keyAlgo) {
|
||||
this.algo = keyAlgo;
|
||||
}
|
||||
public String keyAlgo() {
|
||||
return algo;
|
||||
}
|
||||
public static KeyType lookup(String name)
|
||||
throws InvalidKeyException, ProviderException {
|
||||
if (name == null) {
|
||||
throw new InvalidKeyException("Null key algorithm");
|
||||
}
|
||||
for (KeyType kt : KeyType.values()) {
|
||||
if (kt.keyAlgo().equalsIgnoreCase(name)) {
|
||||
return kt;
|
||||
}
|
||||
}
|
||||
// no match
|
||||
throw new ProviderException("Unsupported algorithm " + name);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkParamsAgainstType(KeyType type,
|
||||
AlgorithmParameterSpec paramSpec) throws ProviderException {
|
||||
switch (type) {
|
||||
case RSA:
|
||||
if (paramSpec != null) {
|
||||
throw new ProviderException("null params expected for " +
|
||||
type.keyAlgo());
|
||||
}
|
||||
break;
|
||||
case PSS:
|
||||
if ((paramSpec != null) &&
|
||||
!(paramSpec instanceof PSSParameterSpec)) {
|
||||
throw new ProviderException
|
||||
("PSSParmeterSpec expected for " + type.keyAlgo());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ProviderException
|
||||
("Unsupported RSA algorithm " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public static AlgorithmId createAlgorithmId(KeyType type,
|
||||
AlgorithmParameterSpec paramSpec) throws ProviderException {
|
||||
|
||||
checkParamsAgainstType(type, paramSpec);
|
||||
|
||||
ObjectIdentifier oid = null;
|
||||
AlgorithmParameters params = null;
|
||||
try {
|
||||
switch (type) {
|
||||
case RSA:
|
||||
oid = AlgorithmId.RSAEncryption_oid;
|
||||
break;
|
||||
case PSS:
|
||||
if (paramSpec != null) {
|
||||
params = AlgorithmParameters.getInstance(type.keyAlgo());
|
||||
params.init(paramSpec);
|
||||
}
|
||||
oid = AlgorithmId.RSASSA_PSS_oid;
|
||||
break;
|
||||
default:
|
||||
throw new ProviderException
|
||||
("Unsupported RSA algorithm " + type);
|
||||
}
|
||||
AlgorithmId result;
|
||||
if (params == null) {
|
||||
result = new AlgorithmId(oid);
|
||||
} else {
|
||||
result = new AlgorithmId(oid, params);
|
||||
}
|
||||
return result;
|
||||
} catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
|
||||
// should not happen
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static AlgorithmParameterSpec getParamSpec(AlgorithmId algid)
|
||||
throws ProviderException {
|
||||
if (algid == null) {
|
||||
throw new ProviderException("AlgorithmId should not be null");
|
||||
}
|
||||
return getParamSpec(algid.getParameters());
|
||||
}
|
||||
|
||||
public static AlgorithmParameterSpec getParamSpec(AlgorithmParameters params)
|
||||
throws ProviderException {
|
||||
if (params == null) return null;
|
||||
|
||||
try {
|
||||
String algName = params.getAlgorithm();
|
||||
KeyType type = KeyType.lookup(algName);
|
||||
Class<? extends AlgorithmParameterSpec> specCls;
|
||||
switch (type) {
|
||||
case RSA:
|
||||
throw new ProviderException("No params accepted for " +
|
||||
type.keyAlgo());
|
||||
case PSS:
|
||||
specCls = PSSParameterSpec.class;
|
||||
break;
|
||||
default:
|
||||
throw new ProviderException("Unsupported RSA algorithm: " + algName);
|
||||
}
|
||||
return params.getParameterSpec(specCls);
|
||||
} catch (ProviderException pe) {
|
||||
// pass it up
|
||||
throw pe;
|
||||
} catch (Exception e) {
|
||||
throw new ProviderException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/sun/security/rsa/SunRsaSign.java
Normal file
61
jdkSrc/jdk8/sun/security/rsa/SunRsaSign.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
/**
|
||||
* Provider class for the RSA signature provider. Supports RSA keyfactory,
|
||||
* keypair generation, and RSA signatures.
|
||||
*
|
||||
* @since 1.5
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class SunRsaSign extends Provider {
|
||||
|
||||
private static final long serialVersionUID = 866040293550393045L;
|
||||
|
||||
public SunRsaSign() {
|
||||
super("SunRsaSign", 1.8d, "Sun RSA signature provider");
|
||||
|
||||
// if there is no security manager installed, put directly into
|
||||
// the provider. Otherwise, create a temporary map and use a
|
||||
// doPrivileged() call at the end to transfer the contents
|
||||
if (System.getSecurityManager() == null) {
|
||||
SunRsaSignEntries.putEntries(this);
|
||||
} else {
|
||||
// use LinkedHashMap to preserve the order of the PRNGs
|
||||
Map<Object, Object> map = new HashMap<>();
|
||||
SunRsaSignEntries.putEntries(map);
|
||||
AccessController.doPrivileged(new PutAllAction(this, map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
135
jdkSrc/jdk8/sun/security/rsa/SunRsaSignEntries.java
Normal file
135
jdkSrc/jdk8/sun/security/rsa/SunRsaSignEntries.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.rsa;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Defines the entries of the SunRsaSign provider.
|
||||
*
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
public final class SunRsaSignEntries {
|
||||
|
||||
private SunRsaSignEntries() {
|
||||
// empty
|
||||
}
|
||||
|
||||
public static void putEntries(Map<Object, Object> map) {
|
||||
|
||||
// main algorithms
|
||||
map.put("KeyFactory.RSA",
|
||||
"sun.security.rsa.RSAKeyFactory$Legacy");
|
||||
map.put("KeyPairGenerator.RSA",
|
||||
"sun.security.rsa.RSAKeyPairGenerator$Legacy");
|
||||
map.put("Signature.MD2withRSA",
|
||||
"sun.security.rsa.RSASignature$MD2withRSA");
|
||||
map.put("Signature.MD5withRSA",
|
||||
"sun.security.rsa.RSASignature$MD5withRSA");
|
||||
map.put("Signature.SHA1withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA1withRSA");
|
||||
map.put("Signature.SHA224withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA224withRSA");
|
||||
map.put("Signature.SHA256withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA256withRSA");
|
||||
map.put("Signature.SHA384withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA384withRSA");
|
||||
map.put("Signature.SHA512withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA512withRSA");
|
||||
map.put("Signature.SHA512/224withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA512_224withRSA");
|
||||
map.put("Signature.SHA512/256withRSA",
|
||||
"sun.security.rsa.RSASignature$SHA512_256withRSA");
|
||||
|
||||
map.put("KeyFactory.RSASSA-PSS",
|
||||
"sun.security.rsa.RSAKeyFactory$PSS");
|
||||
map.put("KeyPairGenerator.RSASSA-PSS",
|
||||
"sun.security.rsa.RSAKeyPairGenerator$PSS");
|
||||
map.put("Signature.RSASSA-PSS",
|
||||
"sun.security.rsa.RSAPSSSignature");
|
||||
map.put("AlgorithmParameters.RSASSA-PSS",
|
||||
"sun.security.rsa.PSSParameters");
|
||||
|
||||
// attributes for supported key classes
|
||||
String rsaKeyClasses = "java.security.interfaces.RSAPublicKey" +
|
||||
"|java.security.interfaces.RSAPrivateKey";
|
||||
map.put("Signature.MD2withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.MD5withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA1withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA224withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA256withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA384withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA512withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA512/224withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.SHA512/256withRSA SupportedKeyClasses", rsaKeyClasses);
|
||||
map.put("Signature.RSASSA-PSS SupportedKeyClasses", rsaKeyClasses);
|
||||
|
||||
// aliases
|
||||
map.put("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA");
|
||||
map.put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA");
|
||||
|
||||
map.put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA");
|
||||
map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA1withRSA");
|
||||
map.put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.14", "SHA224withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.14", "SHA224withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.15", "SHA512/224withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.15", "SHA512/224withRSA");
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.16", "SHA512/256withRSA");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.16", "SHA512/256withRSA");
|
||||
|
||||
map.put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
map.put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
|
||||
map.put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
map.put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
|
||||
map.put("Alg.Alias.Signature.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
map.put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
|
||||
map.put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
map.put("Alg.Alias.AlgorithmParameters.OID.1.2.840.113549.1.1.10", "RSASSA-PSS");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user