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
19652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Rootimport java.security.MessageDigestSpi;
2008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.NoSuchAlgorithmException;
2108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
2588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Rootpublic class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable {
26652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    private OpenSSLDigestContext ctx;
2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
2808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
29079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
30e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom     */
3138c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice    private final long evp_md;
32079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom
33079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    /**
34079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     * Holds the output size of the message digest.
35079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom     */
36079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    private final int size;
37e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom
38e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom    /**
3908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Holds a dummy buffer for writing single bytes to the digest.
4008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
415763f15af2a820056075dd9007d03d3e855a27adBrian Carlstrom    private final byte[] singleByte = new byte[1];
4208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
44652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root     * Creates a new OpenSSLMessageDigest instance for the given algorithm name.
4508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
46652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException {
47079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        this.evp_md = evp_md;
48079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        this.size = size;
49652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root
50652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
51652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    }
52652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root
5388b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    private OpenSSLMessageDigestJDK(long evp_md, int size, OpenSSLDigestContext ctx) {
5488b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.evp_md = evp_md;
5588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.size = size;
5688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        this.ctx = ctx;
5788b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    }
5888b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root
59652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root    private final void resetContext() {
60652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        OpenSSLDigestContext ctxLocal = new OpenSSLDigestContext(NativeCrypto.EVP_MD_CTX_create());
61652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        NativeCrypto.EVP_MD_CTX_init(ctxLocal);
62652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        NativeCrypto.EVP_DigestInit(ctxLocal, evp_md);
63652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        ctx = ctxLocal;
6408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
6508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
6708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineReset() {
68652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
6908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
7008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
7208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected int engineGetDigestLength() {
73079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        return size;
7408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
7508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
7708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineUpdate(byte input) {
7808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        singleByte[0] = input;
7908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        engineUpdate(singleByte, 0, 1);
8008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
8108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
8308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected void engineUpdate(byte[] input, int offset, int len) {
84652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len);
85079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    }
86079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom
87079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    @Override
88079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom    protected byte[] engineDigest() {
89652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        final byte[] result = new byte[size];
90652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        NativeCrypto.EVP_DigestFinal(ctx, result, 0);
91652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root        resetContext();
92079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        return result;
9308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
9408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
952ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class MD5 extends OpenSSLMessageDigestJDK {
9638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
97079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
9808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public MD5() throws NoSuchAlgorithmException {
99652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
10008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
10108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
10273f1fad27323ed00b318de046cfe43236625af09Elliott Hughes
1032ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA1 extends OpenSSLMessageDigestJDK {
10438c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
105079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
10608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public SHA1() throws NoSuchAlgorithmException {
107652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
10808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
10908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11073f1fad27323ed00b318de046cfe43236625af09Elliott Hughes
111d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    public static class SHA224 extends OpenSSLMessageDigestJDK {
112d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224");
113d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
114d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        public SHA224() throws NoSuchAlgorithmException {
115652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
116d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root        }
117d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root    }
118d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root
1192ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA256 extends OpenSSLMessageDigestJDK {
12038c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
121079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
12208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public SHA256() throws NoSuchAlgorithmException {
123652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
12408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
12508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
126af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom
1272ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA384 extends OpenSSLMessageDigestJDK {
12838c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
129079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
130af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        public SHA384() throws NoSuchAlgorithmException {
131652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
132af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        }
133af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom    }
134af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom
1352ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom    public static class SHA512 extends OpenSSLMessageDigestJDK {
13638c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
137079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
138af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        public SHA512() throws NoSuchAlgorithmException {
139652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root            super(EVP_MD, SIZE);
140af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom        }
141af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom    }
14288b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root
14388b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    @Override
14488b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    public Object clone() {
14588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        OpenSSLDigestContext ctxCopy = new OpenSSLDigestContext(NativeCrypto.EVP_MD_CTX_create());
14688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        NativeCrypto.EVP_MD_CTX_init(ctxCopy);
14788b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        NativeCrypto.EVP_MD_CTX_copy(ctxCopy, ctx);
14888b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root        return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy);
14988b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root    }
15008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
151