OpenSSLMessageDigestJDK.java revision 49ebea12f4954f3dbcd16a33a8fa98532d29f8c9
1db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom/*
2db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * Copyright (C) 2008 The Android Open Source Project
3db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom *
4db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
5db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * you may not use this file except in compliance with the License.
6db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * You may obtain a copy of the License at
7db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom *
8db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
9db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom *
10db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
11db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
12db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * See the License for the specific language governing permissions and
14db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom * limitations under the License.
15db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom */
16db9ae4fb599a534bd0703bec27fccd4493b04be7Brian Carlstrom
17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt;
1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubinimport java.nio.ByteBuffer;
20652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Rootimport java.security.MessageDigestSpi;
2108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.NoSuchAlgorithmException;
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
2688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Rootpublic class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable {
2775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin    private final NativeRef.EVP_MD_CTX ctx;
2808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
30079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
31e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom     */
3238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice    private final long evp_md;
33079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom
34079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    /**
35079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     * Holds the output size of the message digest.
36079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     */
37079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    private final int size;
38e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom
39e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom    /**
4008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Holds a dummy buffer for writing single bytes to the digest.
4108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
425763f15af2a820056075dd9007d03d3e855a27adBrian Carlstrom    private final byte[] singleByte = new byte[1];
4308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
4575d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin     * Whether the digest struct has been initialized inside EVP_MD_CTX.
4675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin     */
4775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin    private boolean digestInitializedInContext;
4875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin
4975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin    /**
50652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root     * Creates a new OpenSSLMessageDigest instance for the given algorithm name.
5108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
52652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException {
53079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        this.evp_md = evp_md;
54079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        this.size = size;
5575d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
5675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        this.ctx = ctxLocal;
57652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    }
58652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root
5975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin    private OpenSSLMessageDigestJDK(long evp_md, int size, NativeRef.EVP_MD_CTX ctx,
6075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin            boolean digestInitializedInContext) {
6188b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.evp_md = evp_md;
6288b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.size = size;
6388b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.ctx = ctx;
6475d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        this.digestInitializedInContext = digestInitializedInContext;
6588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    }
6688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root
6775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin    private void ensureDigestInitializedInContext() {
6875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        if (!digestInitializedInContext) {
6975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin            final NativeRef.EVP_MD_CTX ctxLocal = ctx;
7067cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin            NativeCrypto.EVP_DigestInit_ex(ctxLocal, evp_md);
7175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin            digestInitializedInContext = true;
7275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        }
7308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
7408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
7608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineReset() {
7775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        // Reset to the same state as at the end of the <init>(long evp_md, int size). We can avoid
7875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        // allocating a new EVP_MD_CTX by invoking EVP_MD_CTX_cleanup on the existing one.
7975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        // EVP_MD_CTX_cleanup cleans up and reinitializes the EVP_MD_CTX.
8075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        final NativeRef.EVP_MD_CTX ctxLocal = ctx;
8175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        NativeCrypto.EVP_MD_CTX_cleanup(ctxLocal);
8275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        digestInitializedInContext = false;
8308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
8408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
8608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected int engineGetDigestLength() {
87079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        return size;
8808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
8908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
9108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineUpdate(byte input) {
9208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        singleByte[0] = input;
9308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        engineUpdate(singleByte, 0, 1);
9408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
9508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
9708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineUpdate(byte[] input, int offset, int len) {
9875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        ensureDigestInitializedInContext();
99652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len);
100079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    }
101079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom
102079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    @Override
10391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin    protected void engineUpdate(ByteBuffer input) {
10491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        // Optimization: Avoid copying/allocation for direct buffers because their contents are
10591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        // stored as a contiguous region in memory and thus can be efficiently accessed from native
10691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        // code.
10791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
10891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        if (!input.hasRemaining()) {
10991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            return;
11091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        }
11191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
11291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        if (!input.isDirect()) {
11391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            super.engineUpdate(input);
11491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            return;
11591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        }
11691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
11791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        long baseAddress = NativeCrypto.getDirectBufferAddress(input);
11891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        if (baseAddress == 0) {
11991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            // Direct buffer's contents can't be accessed from JNI  -- superclass's implementation
12091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            // is good enough to handle this.
12191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            super.engineUpdate(input);
12291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin            return;
12391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        }
12491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
12591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        // Digest the contents between Buffer's position and limit (remaining() number of bytes)
12691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        int position = input.position();
12749ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        if (position < 0) {
12849ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin            throw new RuntimeException("Negative position");
12991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        }
13049ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        long ptr = baseAddress + position;
13191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        int len = input.remaining();
13249ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin        if (len < 0) {
13349ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin            throw new RuntimeException("Negative remaining amount");
13491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        }
13591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
13675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        ensureDigestInitializedInContext();
13791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        NativeCrypto.EVP_DigestUpdateDirect(ctx, ptr, len);
13891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin        input.position(position + len);
13991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin    }
14091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin
14191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin    @Override
142079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    protected byte[] engineDigest() {
14375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        ensureDigestInitializedInContext();
144652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        final byte[] result = new byte[size];
14567cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin        NativeCrypto.EVP_DigestFinal_ex(ctx, result, 0);
14675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin
14775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        // Optimized reset path:
14875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        // 1. No need to wipe EVP_MD_CTX because EVP_DigestFinal_ex has already cleansed any
14975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        //    sensitive state from it.
15067cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin        // 2. Require EVP_DigestInit_ex to be invoked before this MessageDigestSpi starts computing
15167cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin        //    a new digest.
15275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        digestInitializedInContext = false;
15375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin
154079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        return result;
15508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
15608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1572ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class MD5 extends OpenSSLMessageDigestJDK {
15838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
159079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
16008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public MD5() throws NoSuchAlgorithmException {
161652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
16208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
16308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
16473f1fad27323ed00b318de046cfe43236625af09Elliott Hughes
1652ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA1 extends OpenSSLMessageDigestJDK {
16638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
167079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
16808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public SHA1() throws NoSuchAlgorithmException {
169652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
17008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
17108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
17273f1fad27323ed00b318de046cfe43236625af09Elliott Hughes
173d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    public static class SHA224 extends OpenSSLMessageDigestJDK {
174d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
175d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
176d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        public SHA224() throws NoSuchAlgorithmException {
177652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
178d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        }
179d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    }
180d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root
1812ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA256 extends OpenSSLMessageDigestJDK {
18238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
183079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
18408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public SHA256() throws NoSuchAlgorithmException {
185652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
18608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
18708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
188af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom
1892ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA384 extends OpenSSLMessageDigestJDK {
19038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
191079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
192af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        public SHA384() throws NoSuchAlgorithmException {
193652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
194af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        }
195af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom    }
196af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom
1972ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA512 extends OpenSSLMessageDigestJDK {
19838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
199079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
200af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        public SHA512() throws NoSuchAlgorithmException {
201652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
202af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        }
203af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom    }
20488b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root
20588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    @Override
20688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    public Object clone() {
2074bff0a15ae03c8a3e1ae95590cc8c4240837bff6Kenny Root        NativeRef.EVP_MD_CTX ctxCopy = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
20867cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin        // EVP_MD_CTX_copy_ex requires that the digest struct of source EVP_MD_CTX is initialized.
20967cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin        // There's no need to invoke EVP_MD_CTX_copy_ex when the digest struct isn't initialized.
21075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        if (digestInitializedInContext) {
21167cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin            NativeCrypto.EVP_MD_CTX_copy_ex(ctxCopy, ctx);
21275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        }
21375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin        return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy, digestInitializedInContext);
21488b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    }
21508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
216