• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 /*
3  * Copyright (C) 2008 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.org.conscrypt;
19 
20 import java.nio.ByteBuffer;
21 import java.security.MessageDigestSpi;
22 import java.security.NoSuchAlgorithmException;
23 
24 /**
25  * Implements the JDK MessageDigest interface using OpenSSL's EVP API.
26  * @hide This class is not part of the Android public SDK API
27  */
28 @libcore.api.IntraCoreApi
29 @Internal
30 public class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable {
31     private final NativeRef.EVP_MD_CTX ctx;
32 
33     /**
34      * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
35      */
36     private final long evp_md;
37 
38     /**
39      * Holds the output size of the message digest.
40      */
41     private final int size;
42 
43     /**
44      * Holds a dummy buffer for writing single bytes to the digest.
45      */
46     private final byte[] singleByte = new byte[1];
47 
48     /**
49      * Whether the digest struct has been initialized inside EVP_MD_CTX.
50      */
51     private boolean digestInitializedInContext;
52 
53     /**
54      * Creates a new OpenSSLMessageDigest instance for the given algorithm name.
55      */
OpenSSLMessageDigestJDK(long evp_md, int size)56     private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException {
57         this.evp_md = evp_md;
58         this.size = size;
59         NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
60         this.ctx = ctxLocal;
61     }
62 
OpenSSLMessageDigestJDK(long evp_md, int size, NativeRef.EVP_MD_CTX ctx, boolean digestInitializedInContext)63     private OpenSSLMessageDigestJDK(long evp_md, int size, NativeRef.EVP_MD_CTX ctx,
64             boolean digestInitializedInContext) {
65         this.evp_md = evp_md;
66         this.size = size;
67         this.ctx = ctx;
68         this.digestInitializedInContext = digestInitializedInContext;
69     }
70 
ensureDigestInitializedInContext()71     private synchronized void ensureDigestInitializedInContext() {
72         if (!digestInitializedInContext) {
73             final NativeRef.EVP_MD_CTX ctxLocal = ctx;
74             NativeCrypto.EVP_DigestInit_ex(ctxLocal, evp_md);
75             digestInitializedInContext = true;
76         }
77     }
78 
79     @Override
engineReset()80     protected synchronized void engineReset() {
81         // Reset to the same state as at the end of the <init>(long evp_md, int size). We can avoid
82         // allocating a new EVP_MD_CTX by invoking EVP_MD_CTX_cleanup on the existing one.
83         // EVP_MD_CTX_cleanup cleans up and reinitializes the EVP_MD_CTX.
84         final NativeRef.EVP_MD_CTX ctxLocal = ctx;
85         NativeCrypto.EVP_MD_CTX_cleanup(ctxLocal);
86         digestInitializedInContext = false;
87     }
88 
89     @Override
engineGetDigestLength()90     protected int engineGetDigestLength() {
91         return size;
92     }
93 
94     @Override
engineUpdate(byte input)95     protected synchronized void engineUpdate(byte input) {
96         singleByte[0] = input;
97         engineUpdate(singleByte, 0, 1);
98     }
99 
100     @Override
engineUpdate(byte[] input, int offset, int len)101     protected synchronized void engineUpdate(byte[] input, int offset, int len) {
102         ensureDigestInitializedInContext();
103         NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len);
104     }
105 
106     @Override
engineUpdate(ByteBuffer input)107     protected synchronized void engineUpdate(ByteBuffer input) {
108         // Optimization: Avoid copying/allocation for direct buffers because their contents are
109         // stored as a contiguous region in memory and thus can be efficiently accessed from native
110         // code.
111 
112         if (!input.hasRemaining()) {
113             return;
114         }
115 
116         if (!input.isDirect()) {
117             super.engineUpdate(input);
118             return;
119         }
120 
121         long baseAddress = NativeCrypto.getDirectBufferAddress(input);
122         if (baseAddress == 0) {
123             // Direct buffer's contents can't be accessed from JNI  -- superclass's implementation
124             // is good enough to handle this.
125             super.engineUpdate(input);
126             return;
127         }
128 
129         // Digest the contents between Buffer's position and limit (remaining() number of bytes)
130         int position = input.position();
131         if (position < 0) {
132             throw new RuntimeException("Negative position");
133         }
134         long ptr = baseAddress + position;
135         int len = input.remaining();
136         if (len < 0) {
137             throw new RuntimeException("Negative remaining amount");
138         }
139 
140         ensureDigestInitializedInContext();
141         NativeCrypto.EVP_DigestUpdateDirect(ctx, ptr, len);
142         input.position(position + len);
143     }
144 
145     @Override
engineDigest()146     protected synchronized byte[] engineDigest() {
147         ensureDigestInitializedInContext();
148         final byte[] result = new byte[size];
149         NativeCrypto.EVP_DigestFinal_ex(ctx, result, 0);
150 
151         // Optimized reset path:
152         // 1. No need to wipe EVP_MD_CTX because EVP_DigestFinal_ex has already cleansed any
153         //    sensitive state from it.
154         // 2. Require EVP_DigestInit_ex to be invoked before this MessageDigestSpi starts computing
155         //    a new digest.
156         digestInitializedInContext = false;
157 
158         return result;
159     }
160 
161     /**
162      * @hide This class is not part of the Android public SDK API
163      */
164     @libcore.api.IntraCoreApi
165     public static final class MD5 extends OpenSSLMessageDigestJDK {
166         @libcore.api.IntraCoreApi
MD5()167         public MD5() throws NoSuchAlgorithmException {
168             super(EvpMdRef.MD5.EVP_MD, EvpMdRef.MD5.SIZE_BYTES);
169         }
170     }
171 
172     /**
173      * @hide This class is not part of the Android public SDK API
174      */
175     @libcore.api.IntraCoreApi
176     public static final class SHA1 extends OpenSSLMessageDigestJDK {
177         @libcore.api.IntraCoreApi
SHA1()178         public SHA1() throws NoSuchAlgorithmException {
179             super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.SIZE_BYTES);
180         }
181     }
182 
183     /**
184      * @hide This class is not part of the Android public SDK API
185      */
186     @libcore.api.IntraCoreApi
187     public static final class SHA224 extends OpenSSLMessageDigestJDK {
188         @libcore.api.IntraCoreApi
SHA224()189         public SHA224() throws NoSuchAlgorithmException {
190             super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.SIZE_BYTES);
191         }
192     }
193 
194     /**
195      * @hide This class is not part of the Android public SDK API
196      */
197     @libcore.api.IntraCoreApi
198     public static final class SHA256 extends OpenSSLMessageDigestJDK {
199         @libcore.api.IntraCoreApi
SHA256()200         public SHA256() throws NoSuchAlgorithmException {
201             super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.SIZE_BYTES);
202         }
203     }
204 
205     /**
206      * @hide This class is not part of the Android public SDK API
207      */
208     @libcore.api.IntraCoreApi
209     public static final class SHA384 extends OpenSSLMessageDigestJDK {
210         @libcore.api.IntraCoreApi
SHA384()211         public SHA384() throws NoSuchAlgorithmException {
212             super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.SIZE_BYTES);
213         }
214     }
215 
216     /**
217      * @hide This class is not part of the Android public SDK API
218      */
219     @libcore.api.IntraCoreApi
220     public static final class SHA512 extends OpenSSLMessageDigestJDK {
221         @libcore.api.IntraCoreApi
SHA512()222         public SHA512() throws NoSuchAlgorithmException {
223             super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES);
224         }
225     }
226 
227     @Override
clone()228     public Object clone() {
229         NativeRef.EVP_MD_CTX ctxCopy = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
230         // EVP_MD_CTX_copy_ex requires that the digest struct of source EVP_MD_CTX is initialized.
231         // There's no need to invoke EVP_MD_CTX_copy_ex when the digest struct isn't initialized.
232         if (digestInitializedInContext) {
233             NativeCrypto.EVP_MD_CTX_copy_ex(ctxCopy, ctx);
234         }
235         return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy, digestInitializedInContext);
236     }
237 }
238