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