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.conscrypt; 18 19import java.security.MessageDigestSpi; 20import java.security.NoSuchAlgorithmException; 21 22/** 23 * Implements the JDK MessageDigest interface using OpenSSL's EVP API. 24 */ 25public class OpenSSLMessageDigestJDK extends MessageDigestSpi implements Cloneable { 26 private OpenSSLDigestContext ctx; 27 28 /** 29 * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1"); 30 */ 31 private final long evp_md; 32 33 /** 34 * Holds the output size of the message digest. 35 */ 36 private final int size; 37 38 /** 39 * Holds a dummy buffer for writing single bytes to the digest. 40 */ 41 private final byte[] singleByte = new byte[1]; 42 43 /** 44 * Creates a new OpenSSLMessageDigest instance for the given algorithm name. 45 */ 46 private OpenSSLMessageDigestJDK(long evp_md, int size) throws NoSuchAlgorithmException { 47 this.evp_md = evp_md; 48 this.size = size; 49 50 resetContext(); 51 } 52 53 private OpenSSLMessageDigestJDK(long evp_md, int size, OpenSSLDigestContext ctx) { 54 this.evp_md = evp_md; 55 this.size = size; 56 this.ctx = ctx; 57 } 58 59 private final void resetContext() { 60 OpenSSLDigestContext ctxLocal = new OpenSSLDigestContext(NativeCrypto.EVP_MD_CTX_create()); 61 NativeCrypto.EVP_MD_CTX_init(ctxLocal); 62 NativeCrypto.EVP_DigestInit(ctxLocal, evp_md); 63 ctx = ctxLocal; 64 } 65 66 @Override 67 protected void engineReset() { 68 resetContext(); 69 } 70 71 @Override 72 protected int engineGetDigestLength() { 73 return size; 74 } 75 76 @Override 77 protected void engineUpdate(byte input) { 78 singleByte[0] = input; 79 engineUpdate(singleByte, 0, 1); 80 } 81 82 @Override 83 protected void engineUpdate(byte[] input, int offset, int len) { 84 NativeCrypto.EVP_DigestUpdate(ctx, input, offset, len); 85 } 86 87 @Override 88 protected byte[] engineDigest() { 89 final byte[] result = new byte[size]; 90 NativeCrypto.EVP_DigestFinal(ctx, result, 0); 91 resetContext(); 92 return result; 93 } 94 95 public static class MD5 extends OpenSSLMessageDigestJDK { 96 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("md5"); 97 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 98 public MD5() throws NoSuchAlgorithmException { 99 super(EVP_MD, SIZE); 100 } 101 } 102 103 public static class SHA1 extends OpenSSLMessageDigestJDK { 104 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1"); 105 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 106 public SHA1() throws NoSuchAlgorithmException { 107 super(EVP_MD, SIZE); 108 } 109 } 110 111 public static class SHA224 extends OpenSSLMessageDigestJDK { 112 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha224"); 113 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 114 public SHA224() throws NoSuchAlgorithmException { 115 super(EVP_MD, SIZE); 116 } 117 } 118 119 public static class SHA256 extends OpenSSLMessageDigestJDK { 120 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256"); 121 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 122 public SHA256() throws NoSuchAlgorithmException { 123 super(EVP_MD, SIZE); 124 } 125 } 126 127 public static class SHA384 extends OpenSSLMessageDigestJDK { 128 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384"); 129 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 130 public SHA384() throws NoSuchAlgorithmException { 131 super(EVP_MD, SIZE); 132 } 133 } 134 135 public static class SHA512 extends OpenSSLMessageDigestJDK { 136 private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512"); 137 private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD); 138 public SHA512() throws NoSuchAlgorithmException { 139 super(EVP_MD, SIZE); 140 } 141 } 142 143 @Override 144 public Object clone() { 145 OpenSSLDigestContext ctxCopy = new OpenSSLDigestContext(NativeCrypto.EVP_MD_CTX_create()); 146 NativeCrypto.EVP_MD_CTX_init(ctxCopy); 147 NativeCrypto.EVP_MD_CTX_copy(ctxCopy, ctx); 148 return new OpenSSLMessageDigestJDK(evp_md, size, ctxCopy); 149 } 150} 151