OpenSSLMessageDigestJDK.java revision 8acd6134dc84b387608746fbf2054c6d7dcd4f52
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.apache.harmony.xnet.provider.jsse;
18
19import java.security.MessageDigest;
20import java.security.NoSuchAlgorithmException;
21
22/**
23 * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
24 */
25public class OpenSSLMessageDigestJDK extends MessageDigest implements Cloneable {
26
27    /**
28     * Holds a pointer to the native message digest context.
29     */
30    private long ctx;
31
32    /**
33     * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
34     */
35    private final long evp_md;
36
37    /**
38     * Holds the output size of the message digest.
39     */
40    private final int size;
41
42    /**
43     * Holds a dummy buffer for writing single bytes to the digest.
44     */
45    private final byte[] singleByte = new byte[1];
46
47    /**
48     * Creates a new OpenSSLMessageDigest instance for the given algorithm
49     * name.
50     */
51    private OpenSSLMessageDigestJDK(String algorithm, long evp_md, int size)
52            throws NoSuchAlgorithmException {
53        super(algorithm);
54        this.evp_md = evp_md;
55        this.size = size;
56    }
57
58    @Override
59    protected void engineReset() {
60        free();
61    }
62
63    @Override
64    protected int engineGetDigestLength() {
65        return size;
66    }
67
68    @Override
69    protected void engineUpdate(byte input) {
70        singleByte[0] = input;
71        engineUpdate(singleByte, 0, 1);
72    }
73
74    @Override
75    protected void engineUpdate(byte[] input, int offset, int len) {
76        NativeCrypto.EVP_DigestUpdate(getCtx(), input, offset, len);
77    }
78
79    @Override
80    protected byte[] engineDigest() {
81        byte[] result = new byte[size];
82        NativeCrypto.EVP_DigestFinal(getCtx(), result, 0);
83        ctx = 0; // EVP_DigestFinal frees the context as a side effect
84        return result;
85    }
86
87    public Object clone() throws CloneNotSupportedException {
88        OpenSSLMessageDigestJDK d = (OpenSSLMessageDigestJDK) super.clone();
89        d.ctx = NativeCrypto.EVP_MD_CTX_copy(getCtx());
90        return d;
91    }
92
93    private long getCtx() {
94        if (ctx == 0) {
95            ctx = NativeCrypto.EVP_DigestInit(evp_md);
96        }
97        return ctx;
98    }
99
100    private void free() {
101        if (ctx != 0) {
102            NativeCrypto.EVP_MD_CTX_destroy(ctx);
103            ctx = 0;
104        }
105    }
106
107    @Override protected void finalize() throws Throwable {
108        try {
109            free();
110        } finally {
111            super.finalize();
112        }
113    }
114
115    public static class MD5 extends OpenSSLMessageDigestJDK {
116        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
117        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
118        public MD5() throws NoSuchAlgorithmException {
119            super("MD5",EVP_MD, SIZE);
120        }
121    }
122
123    public static class SHA1 extends OpenSSLMessageDigestJDK {
124        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
125        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
126        public SHA1() throws NoSuchAlgorithmException {
127            super("SHA-1", EVP_MD, SIZE);
128        }
129    }
130
131    public static class SHA256 extends OpenSSLMessageDigestJDK {
132        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
133        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
134        public SHA256() throws NoSuchAlgorithmException {
135            super("SHA-256", EVP_MD, SIZE);
136        }
137    }
138
139    public static class SHA384 extends OpenSSLMessageDigestJDK {
140        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
141        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
142        public SHA384() throws NoSuchAlgorithmException {
143            super("SHA-384", EVP_MD, SIZE);
144        }
145    }
146
147    public static class SHA512 extends OpenSSLMessageDigestJDK {
148        private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
149        private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
150        public SHA512() throws NoSuchAlgorithmException {
151            super("SHA-512", EVP_MD, SIZE);
152        }
153    }
154}
155