Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/security/mscapi/CRSACipher.java
32288 views
/*1* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.mscapi;2627import java.math.BigInteger;28import java.security.*;29import java.security.Key;30import java.security.interfaces.*;31import java.security.spec.*;3233import javax.crypto.*;34import javax.crypto.spec.*;3536import sun.security.rsa.RSAKeyFactory;37import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;38import sun.security.util.KeyUtil;3940/**41* Cipher implementation using the Microsoft Crypto API.42* Supports RSA en/decryption and signing/verifying using PKCS#1 v1.5 padding.43*44* Objects should be instantiated by calling Cipher.getInstance() using the45* following algorithm name:46*47* . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype)48* is selected based on the en/decryption mode and public/private key used.49*50* We only do one RSA operation per doFinal() call. If the application passes51* more data via calls to update() or doFinal(), we throw an52* IllegalBlockSizeException when doFinal() is called (see JCE API spec).53* Bulk encryption using RSA does not make sense and is not standardized.54*55* Note: RSA keys should be at least 512 bits long56*57* @since 1.658* @author Andreas Sterbenz59* @author Vincent Ryan60*/61public final class CRSACipher extends CipherSpi {6263// constant for an empty byte array64private final static byte[] B0 = new byte[0];6566// mode constant for public key encryption67private final static int MODE_ENCRYPT = 1;68// mode constant for private key decryption69private final static int MODE_DECRYPT = 2;70// mode constant for private key encryption (signing)71private final static int MODE_SIGN = 3;72// mode constant for public key decryption (verifying)73private final static int MODE_VERIFY = 4;7475// constant for PKCS#1 v1.5 RSA76private final static String PAD_PKCS1 = "PKCS1Padding";77private final static int PAD_PKCS1_LENGTH = 11;7879// current mode, one of MODE_* above. Set when init() is called80private int mode;8182// active padding type, one of PAD_* above. Set by setPadding()83private String paddingType;84private int paddingLength = 0;8586// buffer for the data87private byte[] buffer;88// offset into the buffer (number of bytes buffered)89private int bufOfs;9091// size of the output (the length of the key).92private int outputSize;9394// the public key, if we were initialized using a public key95private CKey publicKey;9697// the private key, if we were initialized using a private key98private CKey privateKey;99100// cipher parameter for TLS RSA premaster secret101private AlgorithmParameterSpec spec = null;102103// the source of randomness104private SecureRandom random;105106public CRSACipher() {107paddingType = PAD_PKCS1;108}109110// modes do not make sense for RSA, but allow ECB111// see JCE spec112protected void engineSetMode(String mode) throws NoSuchAlgorithmException {113if (mode.equalsIgnoreCase("ECB") == false) {114throw new NoSuchAlgorithmException("Unsupported mode " + mode);115}116}117118// set the padding type119// see JCE spec120protected void engineSetPadding(String paddingName)121throws NoSuchPaddingException {122if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {123paddingType = PAD_PKCS1;124} else {125throw new NoSuchPaddingException126("Padding " + paddingName + " not supported");127}128}129130// return 0 as block size, we are not a block cipher131// see JCE spec132protected int engineGetBlockSize() {133return 0;134}135136// return the output size137// see JCE spec138protected int engineGetOutputSize(int inputLen) {139return outputSize;140}141142// no iv, return null143// see JCE spec144protected byte[] engineGetIV() {145return null;146}147148// no parameters, return null149// see JCE spec150protected AlgorithmParameters engineGetParameters() {151return null;152}153154// see JCE spec155protected void engineInit(int opmode, Key key, SecureRandom random)156throws InvalidKeyException {157init(opmode, key);158}159160// see JCE spec161@SuppressWarnings("deprecation")162protected void engineInit(int opmode, Key key,163AlgorithmParameterSpec params, SecureRandom random)164throws InvalidKeyException, InvalidAlgorithmParameterException {165166if (params != null) {167if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {168throw new InvalidAlgorithmParameterException(169"Parameters not supported");170}171spec = params;172this.random = random; // for TLS RSA premaster secret173}174init(opmode, key);175}176177// see JCE spec178protected void engineInit(int opmode, Key key,179AlgorithmParameters params, SecureRandom random)180throws InvalidKeyException, InvalidAlgorithmParameterException {181182if (params != null) {183throw new InvalidAlgorithmParameterException184("Parameters not supported");185}186init(opmode, key);187}188189// initialize this cipher190private void init(int opmode, Key key) throws InvalidKeyException {191192boolean encrypt;193194switch (opmode) {195case Cipher.ENCRYPT_MODE:196case Cipher.WRAP_MODE:197paddingLength = PAD_PKCS1_LENGTH;198encrypt = true;199break;200case Cipher.DECRYPT_MODE:201case Cipher.UNWRAP_MODE:202paddingLength = 0; // reset203encrypt = false;204break;205default:206throw new InvalidKeyException("Unknown mode: " + opmode);207}208209if (!(key instanceof CKey)) {210if (key instanceof java.security.interfaces.RSAPublicKey) {211java.security.interfaces.RSAPublicKey rsaKey =212(java.security.interfaces.RSAPublicKey) key;213214// Convert key to MSCAPI format215216BigInteger modulus = rsaKey.getModulus();217BigInteger exponent = rsaKey.getPublicExponent();218219// Check against the local and global values to make sure220// the sizes are ok. Round up to the nearest byte.221RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),222exponent, -1, CKeyPairGenerator.RSA.KEY_SIZE_MAX);223224byte[] modulusBytes = modulus.toByteArray();225byte[] exponentBytes = exponent.toByteArray();226227// Adjust key length due to sign bit228int keyBitLength = (modulusBytes[0] == 0)229? (modulusBytes.length - 1) * 8230: modulusBytes.length * 8;231232byte[] keyBlob = CSignature.RSA.generatePublicKeyBlob(233keyBitLength, modulusBytes, exponentBytes);234235try {236key = CSignature.importPublicKey("RSA", keyBlob, keyBitLength);237238} catch (KeyStoreException e) {239throw new InvalidKeyException(e);240}241242} else {243throw new InvalidKeyException("Unsupported key type: " + key);244}245}246247if (key instanceof PublicKey) {248mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;249publicKey = (CKey)key;250privateKey = null;251outputSize = publicKey.length() / 8;252} else if (key instanceof PrivateKey) {253mode = encrypt ? MODE_SIGN : MODE_DECRYPT;254privateKey = (CKey)key;255publicKey = null;256outputSize = privateKey.length() / 8;257} else {258throw new InvalidKeyException("Unknown key type: " + key);259}260261bufOfs = 0;262buffer = new byte[outputSize];263}264265// internal update method266private void update(byte[] in, int inOfs, int inLen) {267if ((inLen == 0) || (in == null)) {268return;269}270if (bufOfs + inLen > (buffer.length - paddingLength)) {271bufOfs = buffer.length + 1;272return;273}274System.arraycopy(in, inOfs, buffer, bufOfs, inLen);275bufOfs += inLen;276}277278// internal doFinal() method. Here we perform the actual RSA operation279private byte[] doFinal() throws BadPaddingException,280IllegalBlockSizeException {281if (bufOfs > buffer.length) {282throw new IllegalBlockSizeException("Data must not be longer "283+ "than " + (buffer.length - paddingLength) + " bytes");284}285286try {287byte[] data = buffer;288switch (mode) {289case MODE_SIGN:290return encryptDecrypt(data, bufOfs,291privateKey.getHCryptKey(), true);292293case MODE_VERIFY:294return encryptDecrypt(data, bufOfs,295publicKey.getHCryptKey(), false);296297case MODE_ENCRYPT:298return encryptDecrypt(data, bufOfs,299publicKey.getHCryptKey(), true);300301case MODE_DECRYPT:302return encryptDecrypt(data, bufOfs,303privateKey.getHCryptKey(), false);304305default:306throw new AssertionError("Internal error");307}308309} catch (KeyException e) {310throw new ProviderException(e);311312} finally {313bufOfs = 0;314}315}316317// see JCE spec318protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {319update(in, inOfs, inLen);320return B0;321}322323// see JCE spec324protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,325int outOfs) {326update(in, inOfs, inLen);327return 0;328}329330// see JCE spec331protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)332throws BadPaddingException, IllegalBlockSizeException {333update(in, inOfs, inLen);334return doFinal();335}336337// see JCE spec338protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,339int outOfs) throws ShortBufferException, BadPaddingException,340IllegalBlockSizeException {341if (outputSize > out.length - outOfs) {342throw new ShortBufferException343("Need " + outputSize + " bytes for output");344}345update(in, inOfs, inLen);346byte[] result = doFinal();347int n = result.length;348System.arraycopy(result, 0, out, outOfs, n);349return n;350}351352// see JCE spec353protected byte[] engineWrap(Key key) throws InvalidKeyException,354IllegalBlockSizeException {355byte[] encoded = key.getEncoded(); // TODO - unextractable key356if ((encoded == null) || (encoded.length == 0)) {357throw new InvalidKeyException("Could not obtain encoded key");358}359if (encoded.length > buffer.length) {360throw new InvalidKeyException("Key is too long for wrapping");361}362update(encoded, 0, encoded.length);363try {364return doFinal();365} catch (BadPaddingException e) {366// should not occur367throw new InvalidKeyException("Wrapping failed", e);368}369}370371// see JCE spec372@SuppressWarnings("deprecation")373protected java.security.Key engineUnwrap(byte[] wrappedKey,374String algorithm,375int type) throws InvalidKeyException, NoSuchAlgorithmException {376377if (wrappedKey.length > buffer.length) {378throw new InvalidKeyException("Key is too long for unwrapping");379}380381boolean isTlsRsaPremasterSecret =382algorithm.equals("TlsRsaPremasterSecret");383Exception failover = null;384byte[] encoded = null;385386update(wrappedKey, 0, wrappedKey.length);387try {388encoded = doFinal();389} catch (BadPaddingException e) {390if (isTlsRsaPremasterSecret) {391failover = e;392} else {393throw new InvalidKeyException("Unwrapping failed", e);394}395} catch (IllegalBlockSizeException e) {396// should not occur, handled with length check above397throw new InvalidKeyException("Unwrapping failed", e);398}399400if (isTlsRsaPremasterSecret) {401if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {402throw new IllegalStateException(403"No TlsRsaPremasterSecretParameterSpec specified");404}405406// polish the TLS premaster secret407encoded = KeyUtil.checkTlsPreMasterSecretKey(408((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),409((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),410random, encoded, (failover != null));411}412413return constructKey(encoded, algorithm, type);414}415416// see JCE spec417protected int engineGetKeySize(Key key) throws InvalidKeyException {418419if (key instanceof CKey) {420return ((CKey) key).length();421422} else if (key instanceof RSAKey) {423return ((RSAKey) key).getModulus().bitLength();424425} else {426throw new InvalidKeyException("Unsupported key type: " + key);427}428}429430// Construct an X.509 encoded public key.431private static PublicKey constructPublicKey(byte[] encodedKey,432String encodedKeyAlgorithm)433throws InvalidKeyException, NoSuchAlgorithmException {434435try {436KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);437X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);438439return keyFactory.generatePublic(keySpec);440441} catch (NoSuchAlgorithmException nsae) {442throw new NoSuchAlgorithmException("No installed provider " +443"supports the " + encodedKeyAlgorithm + " algorithm", nsae);444445} catch (InvalidKeySpecException ike) {446throw new InvalidKeyException("Cannot construct public key", ike);447}448}449450// Construct a PKCS #8 encoded private key.451private static PrivateKey constructPrivateKey(byte[] encodedKey,452String encodedKeyAlgorithm)453throws InvalidKeyException, NoSuchAlgorithmException {454455try {456KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);457PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);458459return keyFactory.generatePrivate(keySpec);460461} catch (NoSuchAlgorithmException nsae) {462throw new NoSuchAlgorithmException("No installed provider " +463"supports the " + encodedKeyAlgorithm + " algorithm", nsae);464465} catch (InvalidKeySpecException ike) {466throw new InvalidKeyException("Cannot construct private key", ike);467}468}469470// Construct an encoded secret key.471private static SecretKey constructSecretKey(byte[] encodedKey,472String encodedKeyAlgorithm) {473474return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);475}476477private static Key constructKey(byte[] encodedKey,478String encodedKeyAlgorithm,479int keyType) throws InvalidKeyException, NoSuchAlgorithmException {480481switch (keyType) {482case Cipher.PUBLIC_KEY:483return constructPublicKey(encodedKey, encodedKeyAlgorithm);484case Cipher.PRIVATE_KEY:485return constructPrivateKey(encodedKey, encodedKeyAlgorithm);486case Cipher.SECRET_KEY:487return constructSecretKey(encodedKey, encodedKeyAlgorithm);488default:489throw new InvalidKeyException("Unknown key type " + keyType);490}491}492493/*494* Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.495* It expects and returns ciphertext data in big-endian form.496*/497private native static byte[] encryptDecrypt(byte[] data, int dataSize,498long hCryptKey, boolean doEncrypt) throws KeyException;499500}501502503