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. 255070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root * 265070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root * @hide 2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 28dbe082cb70a1ffbe1a693bd583a06ecad585f46dNathan Mittler@Internal 2988b56b0666fe3a702da4edc7b5b58266033c5871Kenny Rootpublic class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable { 3075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin private final NativeRef.EVP_MD_CTX ctx; 3108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 33079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1"); 34e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom */ 3538c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice private final long evp_md; 36079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom 37079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom /** 38079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom * Holds the output size of the message digest. 39079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom */ 40079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom private final int size; 41e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom 42e47676a3143deb907b770a461f42d865f767932cBrian Carlstrom /** 4308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Holds a dummy buffer for writing single bytes to the digest. 4408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 455763f15af2a820056075dd9007d03d3e855a27adBrian Carlstrom private final byte[] singleByte = new byte[1]; 4608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project /** 4875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin * Whether the digest struct has been initialized inside EVP_MD_CTX. 4975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin */ 5075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin private boolean digestInitializedInContext; 5175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin 5275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin /** 53652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root * Creates a new OpenSSLMessageDigest instance for the given algorithm name. 5408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */ 55652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException { 56079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom this.evp_md = evp_md; 57079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom this.size = size; 5875d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create()); 5975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin this.ctx = ctxLocal; 60652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root } 61652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root 6275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin private OpenSSLMessageDigestJDK(long evp_md, int size, NativeRef.EVP_MD_CTX ctx, 6375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin boolean digestInitializedInContext) { 6488b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root this.evp_md = evp_md; 6588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root this.size = size; 6688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root this.ctx = ctx; 6775d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin this.digestInitializedInContext = digestInitializedInContext; 6888b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root } 6988b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root 7075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin private void ensureDigestInitializedInContext() { 7175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin if (!digestInitializedInContext) { 7275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin final NativeRef.EVP_MD_CTX ctxLocal = ctx; 7367cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin NativeCrypto.EVP_DigestInit_ex(ctxLocal, evp_md); 7475d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin digestInitializedInContext = true; 7575d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin } 7608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 7708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 7808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project @Override 7908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project protected void engineReset() { 8075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // Reset to the same state as at the end of the <init>(long evp_md, int size). We can avoid 8175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // allocating a new EVP_MD_CTX by invoking EVP_MD_CTX_cleanup on the existing one. 8275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // EVP_MD_CTX_cleanup cleans up and reinitializes the EVP_MD_CTX. 8375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin final NativeRef.EVP_MD_CTX ctxLocal = ctx; 8475d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin NativeCrypto.EVP_MD_CTX_cleanup(ctxLocal); 8575d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin digestInitializedInContext = false; 8608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 8708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 8808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project @Override 8908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project protected int engineGetDigestLength() { 90079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom return size; 9108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 9308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project @Override 9408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project protected void engineUpdate(byte input) { 9508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project singleByte[0] = input; 9608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project engineUpdate(singleByte, 0, 1); 9708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 9808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 9908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project @Override 10008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project protected void engineUpdate(byte[] input, int offset, int len) { 10175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin ensureDigestInitializedInContext(); 102652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len); 103079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom } 104079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom 105079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom @Override 10691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin protected void engineUpdate(ByteBuffer input) { 10791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // Optimization: Avoid copying/allocation for direct buffers because their contents are 10891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // stored as a contiguous region in memory and thus can be efficiently accessed from native 10991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // code. 11091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 11191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin if (!input.hasRemaining()) { 11291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin return; 11391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 11491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 11591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin if (!input.isDirect()) { 11691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin super.engineUpdate(input); 11791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin return; 11891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 11991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 12091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin long baseAddress = NativeCrypto.getDirectBufferAddress(input); 12191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin if (baseAddress == 0) { 12291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // Direct buffer's contents can't be accessed from JNI -- superclass's implementation 12391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // is good enough to handle this. 12491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin super.engineUpdate(input); 12591fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin return; 12691fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 12791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 12891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin // Digest the contents between Buffer's position and limit (remaining() number of bytes) 12991fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin int position = input.position(); 13049ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin if (position < 0) { 13149ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin throw new RuntimeException("Negative position"); 13291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 13349ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin long ptr = baseAddress + position; 13491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin int len = input.remaining(); 13549ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin if (len < 0) { 13649ebea12f4954f3dbcd16a33a8fa98532d29f8c9Alex Klyubin throw new RuntimeException("Negative remaining amount"); 13791fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 13891fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 13975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin ensureDigestInitializedInContext(); 14091fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin NativeCrypto.EVP_DigestUpdateDirect(ctx, ptr, len); 14191fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin input.position(position + len); 14291fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin } 14391fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin 14491fd701b4587210b794fa1a537c38f306a3241d6Alex Klyubin @Override 145079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom protected byte[] engineDigest() { 14675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin ensureDigestInitializedInContext(); 147652ff53bd48ed61389337a42d8e50cdb7ace0fecKenny Root final byte[] result = new byte[size]; 14867cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin NativeCrypto.EVP_DigestFinal_ex(ctx, result, 0); 14975d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin 15075d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // Optimized reset path: 15175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // 1. No need to wipe EVP_MD_CTX because EVP_DigestFinal_ex has already cleansed any 15275d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin // sensitive state from it. 15367cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin // 2. Require EVP_DigestInit_ex to be invoked before this MessageDigestSpi starts computing 15467cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin // a new digest. 15575d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin digestInitializedInContext = false; 15675d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin 157079fab65ece9d6c13d3f67206550985f5d8439fdBrian Carlstrom return result; 15808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 15908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project 1602ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom public static class MD5 extends OpenSSLMessageDigestJDK { 16108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project public MD5() throws NoSuchAlgorithmException { 162b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.MD5.EVP_MD, EvpMdRef.MD5.SIZE_BYTES); 16308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 16408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 16573f1fad27323ed00b318de046cfe43236625af09Elliott Hughes 1662ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom public static class SHA1 extends OpenSSLMessageDigestJDK { 16708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project public SHA1() throws NoSuchAlgorithmException { 168b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.SHA1.EVP_MD, EvpMdRef.SHA1.SIZE_BYTES); 16908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 17008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 17173f1fad27323ed00b318de046cfe43236625af09Elliott Hughes 172d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root public static class SHA224 extends OpenSSLMessageDigestJDK { 173d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root public SHA224() throws NoSuchAlgorithmException { 174b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.SHA224.EVP_MD, EvpMdRef.SHA224.SIZE_BYTES); 175d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root } 176d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root } 177d2db2c558ef6afc14d59f4a6b547598ff3973597Kenny Root 1782ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom public static class SHA256 extends OpenSSLMessageDigestJDK { 17908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project public SHA256() throws NoSuchAlgorithmException { 180b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.SHA256.EVP_MD, EvpMdRef.SHA256.SIZE_BYTES); 18108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 18208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project } 183af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom 1842ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom public static class SHA384 extends OpenSSLMessageDigestJDK { 185af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom public SHA384() throws NoSuchAlgorithmException { 186b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.SHA384.EVP_MD, EvpMdRef.SHA384.SIZE_BYTES); 187af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom } 188af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom } 189af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom 1902ecdfa100af0c18814445608ac7b2bc1e11ef4b2Brian Carlstrom public static class SHA512 extends OpenSSLMessageDigestJDK { 191af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom public SHA512() throws NoSuchAlgorithmException { 192b234f49221b02ff61705a8cc69dd4fcb8cb1c121Kenny Root super(EvpMdRef.SHA512.EVP_MD, EvpMdRef.SHA512.SIZE_BYTES); 193af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom } 194af957f4171aee023d696a514744942d6a003bdbfBrian Carlstrom } 19588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root 19688b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root @Override 19788b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root public Object clone() { 1984bff0a15ae03c8a3e1ae95590cc8c4240837bff6Kenny Root NativeRef.EVP_MD_CTX ctxCopy = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create()); 19967cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin // EVP_MD_CTX_copy_ex requires that the digest struct of source EVP_MD_CTX is initialized. 20067cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin // There's no need to invoke EVP_MD_CTX_copy_ex when the digest struct isn't initialized. 20175d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin if (digestInitializedInContext) { 20267cf2fcd35de497bb4dd7a2cc9bf2a02f0b06349Alex Klyubin NativeCrypto.EVP_MD_CTX_copy_ex(ctxCopy, ctx); 20375d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin } 20475d8933cc4b5053080612f44f9d975f659d933d2Alex Klyubin return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy, digestInitializedInContext); 20588b56b0666fe3a702da4edc7b5b58266033c5871Kenny Root } 20608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project} 207