Path: blob/master/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java
68250 views
/*1* Copyright (c) 2005, 2021, 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 static final byte[] B0 = new byte[0];6566// mode constant for public key encryption67private static final int MODE_ENCRYPT = 1;68// mode constant for private key decryption69private static final int MODE_DECRYPT = 2;70// mode constant for private key encryption (signing)71private static final int MODE_SIGN = 3;72// mode constant for public key decryption (verifying)73private static final int MODE_VERIFY = 4;7475// constant for PKCS#1 v1.5 RSA76private static final String PAD_PKCS1 = "PKCS1Padding";77private static final 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:206// should never happen; checked by Cipher.init()207throw new AssertionError("Unknown mode: " + opmode);208}209210if (!(key instanceof CKey)) {211if (key instanceof java.security.interfaces.RSAPublicKey) {212java.security.interfaces.RSAPublicKey rsaKey =213(java.security.interfaces.RSAPublicKey) key;214215// Convert key to MSCAPI format216217BigInteger modulus = rsaKey.getModulus();218BigInteger exponent = rsaKey.getPublicExponent();219220// Check against the local and global values to make sure221// the sizes are ok. Round up to the nearest byte.222RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),223exponent, -1, CKeyPairGenerator.RSA.KEY_SIZE_MAX);224225byte[] modulusBytes = modulus.toByteArray();226byte[] exponentBytes = exponent.toByteArray();227228// Adjust key length due to sign bit229int keyBitLength = (modulusBytes[0] == 0)230? (modulusBytes.length - 1) * 8231: modulusBytes.length * 8;232233byte[] keyBlob = CSignature.RSA.generatePublicKeyBlob(234keyBitLength, modulusBytes, exponentBytes);235236try {237key = CSignature.importPublicKey("RSA", keyBlob, keyBitLength);238239} catch (KeyStoreException e) {240throw new InvalidKeyException(e);241}242243} else {244throw new InvalidKeyException("Unsupported key type: " + key);245}246}247248if (key instanceof PublicKey) {249mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;250publicKey = (CKey)key;251privateKey = null;252outputSize = publicKey.length() / 8;253} else if (key instanceof PrivateKey) {254mode = encrypt ? MODE_SIGN : MODE_DECRYPT;255privateKey = (CKey)key;256publicKey = null;257outputSize = privateKey.length() / 8;258} else {259throw new InvalidKeyException("Unknown key type: " + key);260}261262bufOfs = 0;263buffer = new byte[outputSize];264}265266// internal update method267private void update(byte[] in, int inOfs, int inLen) {268if ((inLen == 0) || (in == null)) {269return;270}271if (bufOfs + inLen > (buffer.length - paddingLength)) {272bufOfs = buffer.length + 1;273return;274}275System.arraycopy(in, inOfs, buffer, bufOfs, inLen);276bufOfs += inLen;277}278279// internal doFinal() method. Here we perform the actual RSA operation280private byte[] doFinal() throws BadPaddingException,281IllegalBlockSizeException {282if (bufOfs > buffer.length) {283throw new IllegalBlockSizeException("Data must not be longer "284+ "than " + (buffer.length - paddingLength) + " bytes");285}286287try {288byte[] data = buffer;289switch (mode) {290case MODE_SIGN:291return encryptDecrypt(data, bufOfs,292privateKey.getHCryptKey(), true);293294case MODE_VERIFY:295return encryptDecrypt(data, bufOfs,296publicKey.getHCryptKey(), false);297298case MODE_ENCRYPT:299return encryptDecrypt(data, bufOfs,300publicKey.getHCryptKey(), true);301302case MODE_DECRYPT:303return encryptDecrypt(data, bufOfs,304privateKey.getHCryptKey(), false);305306default:307throw new AssertionError("Internal error");308}309310} catch (KeyException e) {311throw new ProviderException(e);312313} finally {314bufOfs = 0;315}316}317318// see JCE spec319protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {320update(in, inOfs, inLen);321return B0;322}323324// see JCE spec325protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,326int outOfs) {327update(in, inOfs, inLen);328return 0;329}330331// see JCE spec332protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)333throws BadPaddingException, IllegalBlockSizeException {334update(in, inOfs, inLen);335return doFinal();336}337338// see JCE spec339protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,340int outOfs) throws ShortBufferException, BadPaddingException,341IllegalBlockSizeException {342if (outputSize > out.length - outOfs) {343throw new ShortBufferException344("Need " + outputSize + " bytes for output");345}346update(in, inOfs, inLen);347byte[] result = doFinal();348int n = result.length;349System.arraycopy(result, 0, out, outOfs, n);350return n;351}352353// see JCE spec354protected byte[] engineWrap(Key key) throws InvalidKeyException,355IllegalBlockSizeException {356byte[] encoded = key.getEncoded(); // TODO - unextractable key357if ((encoded == null) || (encoded.length == 0)) {358throw new InvalidKeyException("Could not obtain encoded key");359}360if (encoded.length > buffer.length) {361throw new InvalidKeyException("Key is too long for wrapping");362}363update(encoded, 0, encoded.length);364try {365return doFinal();366} catch (BadPaddingException e) {367// should not occur368throw new InvalidKeyException("Wrapping failed", e);369}370}371372// see JCE spec373@SuppressWarnings("deprecation")374protected java.security.Key engineUnwrap(byte[] wrappedKey,375String algorithm,376int type) throws InvalidKeyException, NoSuchAlgorithmException {377378if (wrappedKey.length > buffer.length) {379throw new InvalidKeyException("Key is too long for unwrapping");380}381382boolean isTlsRsaPremasterSecret =383algorithm.equals("TlsRsaPremasterSecret");384Exception failover = null;385byte[] encoded = null;386387update(wrappedKey, 0, wrappedKey.length);388try {389encoded = doFinal();390} catch (BadPaddingException e) {391if (isTlsRsaPremasterSecret) {392failover = e;393} else {394throw new InvalidKeyException("Unwrapping failed", e);395}396} catch (IllegalBlockSizeException e) {397// should not occur, handled with length check above398throw new InvalidKeyException("Unwrapping failed", e);399}400401if (isTlsRsaPremasterSecret) {402if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {403throw new IllegalStateException(404"No TlsRsaPremasterSecretParameterSpec specified");405}406407// polish the TLS premaster secret408encoded = KeyUtil.checkTlsPreMasterSecretKey(409((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),410((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),411random, encoded, (failover != null));412}413414return constructKey(encoded, algorithm, type);415}416417// see JCE spec418protected int engineGetKeySize(Key key) throws InvalidKeyException {419420if (key instanceof CKey) {421return ((CKey) key).length();422423} else if (key instanceof RSAKey) {424return ((RSAKey) key).getModulus().bitLength();425426} else {427throw new InvalidKeyException("Unsupported key type: " + key);428}429}430431// Construct an X.509 encoded public key.432private static PublicKey constructPublicKey(byte[] encodedKey,433String encodedKeyAlgorithm)434throws InvalidKeyException, NoSuchAlgorithmException {435436try {437KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);438X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);439440return keyFactory.generatePublic(keySpec);441442} catch (NoSuchAlgorithmException nsae) {443throw new NoSuchAlgorithmException("No installed provider " +444"supports the " + encodedKeyAlgorithm + " algorithm", nsae);445446} catch (InvalidKeySpecException ike) {447throw new InvalidKeyException("Cannot construct public key", ike);448}449}450451// Construct a PKCS #8 encoded private key.452private static PrivateKey constructPrivateKey(byte[] encodedKey,453String encodedKeyAlgorithm)454throws InvalidKeyException, NoSuchAlgorithmException {455456try {457KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);458PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);459460return keyFactory.generatePrivate(keySpec);461462} catch (NoSuchAlgorithmException nsae) {463throw new NoSuchAlgorithmException("No installed provider " +464"supports the " + encodedKeyAlgorithm + " algorithm", nsae);465466} catch (InvalidKeySpecException ike) {467throw new InvalidKeyException("Cannot construct private key", ike);468}469}470471// Construct an encoded secret key.472private static SecretKey constructSecretKey(byte[] encodedKey,473String encodedKeyAlgorithm) {474475return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);476}477478private static Key constructKey(byte[] encodedKey,479String encodedKeyAlgorithm,480int keyType) throws InvalidKeyException, NoSuchAlgorithmException {481482switch (keyType) {483case Cipher.PUBLIC_KEY:484return constructPublicKey(encodedKey, encodedKeyAlgorithm);485case Cipher.PRIVATE_KEY:486return constructPrivateKey(encodedKey, encodedKeyAlgorithm);487case Cipher.SECRET_KEY:488return constructSecretKey(encodedKey, encodedKeyAlgorithm);489default:490throw new InvalidKeyException("Unknown key type " + keyType);491}492}493494/*495* Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.496* It expects and returns ciphertext data in big-endian form.497*/498private native static byte[] encryptDecrypt(byte[] data, int dataSize,499long hCryptKey, boolean doEncrypt) throws KeyException;500501}502503504