Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Digest.java
41154 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.pkcs11;2627import java.util.*;28import java.nio.ByteBuffer;2930import java.security.*;3132import javax.crypto.SecretKey;3334import sun.nio.ch.DirectBuffer;3536import sun.security.util.MessageDigestSpi2;3738import sun.security.pkcs11.wrapper.*;39import static sun.security.pkcs11.wrapper.PKCS11Constants.*;4041/**42* MessageDigest implementation class. This class currently supports43* MD2, MD5, SHA-1, SHA-2 family (SHA-224, SHA-256, SHA-384, and SHA-512)44* and SHA-3 family (SHA3-224, SHA3-256, SHA3-384, and SHA3-512) of digests.45*46* Note that many digest operations are on fairly small amounts of data47* (less than 100 bytes total). For example, the 2nd hashing in HMAC or48* the PRF in TLS. In order to speed those up, we use some buffering to49* minimize number of the Java->native transitions.50*51* @author Andreas Sterbenz52* @since 1.553*/54final class P11Digest extends MessageDigestSpi implements Cloneable,55MessageDigestSpi2 {5657/* fields initialized, no session acquired */58private static final int S_BLANK = 1;5960/* data in buffer, session acquired, but digest not initialized */61private static final int S_BUFFERED = 2;6263/* session initialized for digesting */64private static final int S_INIT = 3;6566private static final int BUFFER_SIZE = 96;6768// token instance69private final Token token;7071// algorithm name72private final String algorithm;7374// mechanism id object75private final CK_MECHANISM mechanism;7677// length of the digest in bytes78private final int digestLength;7980// associated session, if any81private Session session;8283// current state, one of S_* above84private int state;8586// buffer to reduce number of JNI calls87private byte[] buffer;8889// offset into the buffer90private int bufOfs;9192P11Digest(Token token, String algorithm, long mechanism) {93super();94this.token = token;95this.algorithm = algorithm;96this.mechanism = new CK_MECHANISM(mechanism);97switch ((int)mechanism) {98case (int)CKM_MD2:99case (int)CKM_MD5:100digestLength = 16;101break;102case (int)CKM_SHA_1:103digestLength = 20;104break;105case (int)CKM_SHA224:106case (int)CKM_SHA512_224:107case (int)CKM_SHA3_224:108digestLength = 28;109break;110case (int)CKM_SHA256:111case (int)CKM_SHA512_256:112case (int)CKM_SHA3_256:113digestLength = 32;114break;115case (int)CKM_SHA384:116case (int)CKM_SHA3_384:117digestLength = 48;118break;119case (int)CKM_SHA512:120case (int)CKM_SHA3_512:121digestLength = 64;122break;123default:124throw new ProviderException("Unknown mechanism: " + mechanism);125}126buffer = new byte[BUFFER_SIZE];127state = S_BLANK;128}129130// see JCA spec131protected int engineGetDigestLength() {132return digestLength;133}134135private void fetchSession() {136token.ensureValid();137if (state == S_BLANK) {138try {139session = token.getOpSession();140state = S_BUFFERED;141} catch (PKCS11Exception e) {142throw new ProviderException("No more session available", e);143}144}145}146147// see JCA spec148protected void engineReset() {149token.ensureValid();150151if (session != null) {152if (state == S_INIT && token.explicitCancel == true153&& session.hasObjects() == false) {154session = token.killSession(session);155} else {156session = token.releaseSession(session);157}158}159state = S_BLANK;160bufOfs = 0;161}162163// see JCA spec164protected byte[] engineDigest() {165try {166byte[] digest = new byte[digestLength];167int n = engineDigest(digest, 0, digestLength);168return digest;169} catch (DigestException e) {170throw new ProviderException("internal error", e);171}172}173174// see JCA spec175protected int engineDigest(byte[] digest, int ofs, int len)176throws DigestException {177if (len < digestLength) {178throw new DigestException("Length must be at least " +179digestLength);180}181182fetchSession();183try {184int n;185if (state == S_BUFFERED) {186n = token.p11.C_DigestSingle(session.id(), mechanism, buffer, 0,187bufOfs, digest, ofs, len);188bufOfs = 0;189} else {190if (bufOfs != 0) {191token.p11.C_DigestUpdate(session.id(), 0, buffer, 0,192bufOfs);193bufOfs = 0;194}195n = token.p11.C_DigestFinal(session.id(), digest, ofs, len);196}197if (n != digestLength) {198throw new ProviderException("internal digest length error");199}200return n;201} catch (PKCS11Exception e) {202throw new ProviderException("digest() failed", e);203} finally {204engineReset();205}206}207208// see JCA spec209protected void engineUpdate(byte in) {210byte[] temp = { in };211engineUpdate(temp, 0, 1);212}213214// see JCA spec215protected void engineUpdate(byte[] in, int ofs, int len) {216if (len <= 0) {217return;218}219220fetchSession();221try {222if (state == S_BUFFERED) {223token.p11.C_DigestInit(session.id(), mechanism);224state = S_INIT;225}226if ((bufOfs != 0) && (bufOfs + len > buffer.length)) {227// process the buffered data228token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs);229bufOfs = 0;230}231if (bufOfs + len > buffer.length) {232// process the new data233token.p11.C_DigestUpdate(session.id(), 0, in, ofs, len);234} else {235// buffer the new data236System.arraycopy(in, ofs, buffer, bufOfs, len);237bufOfs += len;238}239} catch (PKCS11Exception e) {240engineReset();241throw new ProviderException("update() failed", e);242}243}244245// Called by SunJSSE via reflection during the SSL 3.0 handshake if246// the master secret is sensitive.247// Note: Change to protected after this method is moved from248// sun.security.util.MessageSpi2 interface to249// java.security.MessageDigestSpi class250public void engineUpdate(SecretKey key) throws InvalidKeyException {251// SunJSSE calls this method only if the key does not have a RAW252// encoding, i.e. if it is sensitive. Therefore, no point in calling253// SecretKeyFactory to try to convert it. Just verify it ourselves.254if (key instanceof P11Key == false) {255throw new InvalidKeyException("Not a P11Key: " + key);256}257P11Key p11Key = (P11Key)key;258if (p11Key.token != token) {259throw new InvalidKeyException("Not a P11Key of this provider: " +260key);261}262263fetchSession();264long p11KeyID = p11Key.getKeyID();265try {266if (state == S_BUFFERED) {267token.p11.C_DigestInit(session.id(), mechanism);268state = S_INIT;269}270271if (bufOfs != 0) {272token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs);273bufOfs = 0;274}275token.p11.C_DigestKey(session.id(), p11KeyID);276} catch (PKCS11Exception e) {277engineReset();278throw new ProviderException("update(SecretKey) failed", e);279} finally {280p11Key.releaseKeyID();281}282}283284// see JCA spec285protected void engineUpdate(ByteBuffer byteBuffer) {286int len = byteBuffer.remaining();287if (len <= 0) {288return;289}290291if (byteBuffer instanceof DirectBuffer == false) {292super.engineUpdate(byteBuffer);293return;294}295296fetchSession();297long addr = ((DirectBuffer)byteBuffer).address();298int ofs = byteBuffer.position();299try {300if (state == S_BUFFERED) {301token.p11.C_DigestInit(session.id(), mechanism);302state = S_INIT;303}304if (bufOfs != 0) {305token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs);306bufOfs = 0;307}308token.p11.C_DigestUpdate(session.id(), addr + ofs, null, 0, len);309byteBuffer.position(ofs + len);310} catch (PKCS11Exception e) {311engineReset();312throw new ProviderException("update() failed", e);313}314}315316public Object clone() throws CloneNotSupportedException {317P11Digest copy = (P11Digest) super.clone();318copy.buffer = buffer.clone();319try {320if (session != null) {321copy.session = copy.token.getOpSession();322}323if (state == S_INIT) {324byte[] stateValues =325token.p11.C_GetOperationState(session.id());326token.p11.C_SetOperationState(copy.session.id(),327stateValues, 0, 0);328}329} catch (PKCS11Exception e) {330throw (CloneNotSupportedException)331(new CloneNotSupportedException(algorithm).initCause(e));332}333return copy;334}335}336337338