1098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom/* 2098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Copyright (C) 2012 The Android Open Source Project 3098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * 4098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 5098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * you may not use this file except in compliance with the License. 6098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * You may obtain a copy of the License at 7098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * 8098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 9098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * 10098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Unless required by applicable law or agreed to in writing, software 11098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 12098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * See the License for the specific language governing permissions and 14098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * limitations under the License. 15098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 16098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 18098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 19098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.AlgorithmParameters; 20098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.InvalidAlgorithmParameterException; 21098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.InvalidKeyException; 22098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.InvalidParameterException; 23098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.Key; 24098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.KeyFactory; 25098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.NoSuchAlgorithmException; 26098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.SecureRandom; 27098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.SignatureException; 28098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.interfaces.RSAPrivateCrtKey; 29098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.interfaces.RSAPrivateKey; 30098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.interfaces.RSAPublicKey; 31098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.spec.AlgorithmParameterSpec; 32098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.spec.InvalidKeySpecException; 33098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.spec.PKCS8EncodedKeySpec; 34098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.security.spec.X509EncodedKeySpec; 35098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport java.util.Arrays; 36a95efb43025a1a7f55c2c09cacce6591f6f727faElliott Hughesimport java.util.Locale; 37098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.BadPaddingException; 38098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.Cipher; 39098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.CipherSpi; 40098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.IllegalBlockSizeException; 41098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.NoSuchPaddingException; 42098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.ShortBufferException; 43098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstromimport javax.crypto.spec.SecretKeySpec; 44c875a50c6c5152f31de58d726c69b93835203511Kenny Rootimport org.conscrypt.util.EmptyArray; 45098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 46098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrompublic abstract class OpenSSLCipherRSA extends CipherSpi { 47098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 48098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * The current OpenSSL key we're operating on. 49098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 50098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private OpenSSLKey key; 51098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 52098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 53098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Current key type: private or public. 54098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 55098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private boolean usingPrivateKey; 56098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 57098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 58098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Current cipher mode: encrypting or decrypting. 59098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 60098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private boolean encrypting; 61098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 62098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 63098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Buffer for operations 64098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 65098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private byte[] buffer; 66098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 67098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 68098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Current offset in the buffer. 69098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 70098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private int bufferOffset; 71098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 72098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 73098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Flag that indicates an exception should be thrown when the input is too 74098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * large during doFinal. 75098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 76098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private boolean inputTooLarge; 77098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 78098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom /** 79098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom * Current padding mode 80098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom */ 81f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley private int padding = NativeConstants.RSA_PKCS1_PADDING; 82098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 83098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected OpenSSLCipherRSA(int padding) { 84098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.padding = padding; 85098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 86098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 87098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 88098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected void engineSetMode(String mode) throws NoSuchAlgorithmException { 89a95efb43025a1a7f55c2c09cacce6591f6f727faElliott Hughes final String modeUpper = mode.toUpperCase(Locale.ROOT); 90098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if ("NONE".equals(modeUpper) || "ECB".equals(modeUpper)) { 91098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return; 92098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 93098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 94098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new NoSuchAlgorithmException("mode not supported: " + mode); 95098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 96098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 97098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 98098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected void engineSetPadding(String padding) throws NoSuchPaddingException { 99a95efb43025a1a7f55c2c09cacce6591f6f727faElliott Hughes final String paddingUpper = padding.toUpperCase(Locale.ROOT); 100098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if ("PKCS1PADDING".equals(paddingUpper)) { 101f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley this.padding = NativeConstants.RSA_PKCS1_PADDING; 102098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return; 103098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 104098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if ("NOPADDING".equals(paddingUpper)) { 105f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley this.padding = NativeConstants.RSA_NO_PADDING; 106098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return; 107098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 108098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 109098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new NoSuchPaddingException("padding not supported: " + padding); 110098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 111098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 112098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 113098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected int engineGetBlockSize() { 1148fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom if (encrypting) { 1158fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom return paddedBlockSizeBytes(); 1168fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom } 1178fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom return keySizeBytes(); 118098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 119098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 120098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 121098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected int engineGetOutputSize(int inputLen) { 1228fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom if (encrypting) { 1238fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom return keySizeBytes(); 1248fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom } 1258fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom return paddedBlockSizeBytes(); 1268fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom } 1278fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom 1288fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom private int paddedBlockSizeBytes() { 1298fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom int paddedBlockSizeBytes = keySizeBytes(); 130f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley if (padding == NativeConstants.RSA_PKCS1_PADDING) { 1318fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom paddedBlockSizeBytes--; // for 0 prefix 1328fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom paddedBlockSizeBytes -= 10; // PKCS1 padding header length 1338fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom } 1348fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom return paddedBlockSizeBytes; 1358fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom } 1368fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom 1378fd5a29af22e9bb626b65bbace66028cb5be86b2Brian Carlstrom private int keySizeBytes() { 138098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (key == null) { 139098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new IllegalStateException("cipher is not initialized"); 140098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 14137e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root return NativeCrypto.RSA_size(this.key.getNativeRef()); 142098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 143098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 144098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 145098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected byte[] engineGetIV() { 146098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return null; 147098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 148098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 149098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 150098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected AlgorithmParameters engineGetParameters() { 151098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return null; 152098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 153098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 154098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom private void engineInitInternal(int opmode, Key key) throws InvalidKeyException { 155098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) { 156098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom encrypting = true; 157098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) { 158098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom encrypting = false; 159098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 160098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidParameterException("Unsupported opmode " + opmode); 161098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 162098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 163098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (key instanceof OpenSSLRSAPrivateKey) { 164098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom OpenSSLRSAPrivateKey rsaPrivateKey = (OpenSSLRSAPrivateKey) key; 165098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom usingPrivateKey = true; 166098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.key = rsaPrivateKey.getOpenSSLKey(); 167098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (key instanceof RSAPrivateCrtKey) { 168098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom RSAPrivateCrtKey rsaPrivateKey = (RSAPrivateCrtKey) key; 169098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom usingPrivateKey = true; 170098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.key = OpenSSLRSAPrivateCrtKey.getInstance(rsaPrivateKey); 171098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (key instanceof RSAPrivateKey) { 172098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key; 173098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom usingPrivateKey = true; 174098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.key = OpenSSLRSAPrivateKey.getInstance(rsaPrivateKey); 175098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (key instanceof OpenSSLRSAPublicKey) { 176098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom OpenSSLRSAPublicKey rsaPublicKey = (OpenSSLRSAPublicKey) key; 177098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom usingPrivateKey = false; 178098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.key = rsaPublicKey.getOpenSSLKey(); 179098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (key instanceof RSAPublicKey) { 180098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom RSAPublicKey rsaPublicKey = (RSAPublicKey) key; 181098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom usingPrivateKey = false; 182098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom this.key = OpenSSLRSAPublicKey.getInstance(rsaPublicKey); 183098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 184098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidKeyException("Need RSA private or public key"); 185098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 186098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 18737e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root buffer = new byte[NativeCrypto.RSA_size(this.key.getNativeRef())]; 18830d2cd7835480c2bf91b91bfbc58bab59048f3b3Kenny Root bufferOffset = 0; 189098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom inputTooLarge = false; 190098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 191098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 192098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 193098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { 194098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom engineInitInternal(opmode, key); 195098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 196098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 197098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 198098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, 199098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { 200098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (params != null) { 201098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidAlgorithmParameterException("unknown param type: " 202098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom + params.getClass().getName()); 203098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 204098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 205098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom engineInitInternal(opmode, key); 206098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 207098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 208098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 209098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) 210098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throws InvalidKeyException, InvalidAlgorithmParameterException { 211098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (params != null) { 212098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidAlgorithmParameterException("unknown param type: " 213098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom + params.getClass().getName()); 214098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 215098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 216098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom engineInitInternal(opmode, key); 217098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 218098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 219098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 220098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { 221098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (bufferOffset + inputLen > buffer.length) { 222098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom inputTooLarge = true; 223098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return EmptyArray.BYTE; 224098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 225098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 226098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom System.arraycopy(input, inputOffset, buffer, bufferOffset, inputLen); 227098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom bufferOffset += inputLen; 228098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return EmptyArray.BYTE; 229098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 230098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 231098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 232098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, 233098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom int outputOffset) throws ShortBufferException { 234098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom engineUpdate(input, inputOffset, inputLen); 235098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return 0; 236098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 237098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 238098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 239098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) 240098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throws IllegalBlockSizeException, BadPaddingException { 241098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (input != null) { 242098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom engineUpdate(input, inputOffset, inputLen); 243098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 244098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 245098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (inputTooLarge) { 246098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new IllegalBlockSizeException("input must be under " + buffer.length + " bytes"); 247098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 248098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 249098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom final byte[] tmpBuf; 250098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (bufferOffset != buffer.length) { 251f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley if (padding == NativeConstants.RSA_NO_PADDING) { 252098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom tmpBuf = new byte[buffer.length]; 253098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom System.arraycopy(buffer, 0, tmpBuf, buffer.length - bufferOffset, bufferOffset); 254098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 255098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom tmpBuf = Arrays.copyOf(buffer, bufferOffset); 256098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 257098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 258098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom tmpBuf = buffer; 259098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 260098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 261098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom byte[] output = new byte[buffer.length]; 262098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom int resultSize; 263098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (encrypting) { 264098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (usingPrivateKey) { 265098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom resultSize = NativeCrypto.RSA_private_encrypt(tmpBuf.length, tmpBuf, output, 26637e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root key.getNativeRef(), padding); 267098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 268098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom resultSize = NativeCrypto.RSA_public_encrypt(tmpBuf.length, tmpBuf, output, 26937e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root key.getNativeRef(), padding); 270098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 271098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 272098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom try { 273098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (usingPrivateKey) { 274098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom resultSize = NativeCrypto.RSA_private_decrypt(tmpBuf.length, tmpBuf, output, 27537e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root key.getNativeRef(), padding); 276098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 277098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom resultSize = NativeCrypto.RSA_public_decrypt(tmpBuf.length, tmpBuf, output, 27837e58bbef60b18389074d8ef8a8c470e47f3d7eeKenny Root key.getNativeRef(), padding); 279098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 280098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } catch (SignatureException e) { 281098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom IllegalBlockSizeException newE = new IllegalBlockSizeException(); 282098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom newE.initCause(e); 283098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw newE; 284098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 285098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 286098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (!encrypting && resultSize != output.length) { 287098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom output = Arrays.copyOf(output, resultSize); 288098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 289098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 290098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom bufferOffset = 0; 291098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return output; 292098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 293098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 294098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 295098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, 296098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom int outputOffset) throws ShortBufferException, IllegalBlockSizeException, 297098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom BadPaddingException { 298098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom byte[] b = engineDoFinal(input, inputOffset, inputLen); 299098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 300098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom final int lastOffset = outputOffset + b.length; 301098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (lastOffset > output.length) { 302098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new ShortBufferException("output buffer is too small " + output.length + " < " 303098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom + lastOffset); 304098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 305098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 306098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom System.arraycopy(b, 0, output, outputOffset, b.length); 307098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return b.length; 308098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 309098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 310098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 311098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { 312098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom try { 313098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom byte[] encoded = key.getEncoded(); 314098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return engineDoFinal(encoded, 0, encoded.length); 315098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } catch (BadPaddingException e) { 316098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom IllegalBlockSizeException newE = new IllegalBlockSizeException(); 317098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom newE.initCause(e); 318098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw newE; 319098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 320098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 321098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 322098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom @Override 323098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 324098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException { 325098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom try { 326098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom byte[] encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); 327098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom if (wrappedKeyType == Cipher.PUBLIC_KEY) { 328098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 329098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return keyFactory.generatePublic(new X509EncodedKeySpec(encoded)); 330098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (wrappedKeyType == Cipher.PRIVATE_KEY) { 331098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); 332098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded)); 333098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else if (wrappedKeyType == Cipher.SECRET_KEY) { 334098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom return new SecretKeySpec(encoded, wrappedKeyAlgorithm); 335098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } else { 336098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new UnsupportedOperationException("wrappedKeyType == " + wrappedKeyType); 337098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 338098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } catch (IllegalBlockSizeException e) { 339098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidKeyException(e); 340098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } catch (BadPaddingException e) { 341098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidKeyException(e); 342098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } catch (InvalidKeySpecException e) { 343098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom throw new InvalidKeyException(e); 344098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 345098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 346098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 347098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom public static class PKCS1 extends OpenSSLCipherRSA { 348098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom public PKCS1() { 349f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley super(NativeConstants.RSA_PKCS1_PADDING); 350098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 351098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 352098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom 353098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom public static class Raw extends OpenSSLCipherRSA { 354098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom public Raw() { 355f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley super(NativeConstants.RSA_NO_PADDING); 356098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 357098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom } 358098faff2d757d91d9fd387a16053f55e1b4d5a5cBrian Carlstrom} 359