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