266 lines · 8.0 KB · Java
RawDownload
/* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.pkcs11; import java.util.*;import java.nio.ByteBuffer; import java.security.*;import java.security.spec.AlgorithmParameterSpec; import javax.crypto.MacSpi; import sun.nio.ch.DirectBuffer; import sun.security.pkcs11.wrapper.*;import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * MAC implementation class. This class currently supports HMAC using * MD5, SHA-1, SHA-256, SHA-384, and SHA-512 and the SSL3 MAC using MD5 * and SHA-1. * * Note that unlike other classes (e.g. Signature), this does not * composite various operations if the token only supports part of the * required functionality. The MAC implementations in SunJCE already * do exactly that by implementing an MAC on top of MessageDigests. We * could not do any better than they. * * @author  Andreas Sterbenz * @since   1.5 */final class P11Mac extends MacSpi {     /* unitialized, all fields except session have arbitrary values */    private final static int S_UNINIT   = 1;     /* session initialized, no data processed yet */    private final static int S_RESET    = 2;     /* session initialized, data processed */    private final static int S_UPDATE   = 3;     /* transitional state after doFinal() before we go to S_UNINIT */    private final static int S_DOFINAL  = 4;     // token instance    private final Token token;     // algorithm name    private final String algorithm;     // mechanism id    private final long mechanism;     // mechanism object    private final CK_MECHANISM ckMechanism;     // length of the MAC in bytes    private final int macLength;     // key instance used, if operation active    private P11Key p11Key;     // associated session, if any    private Session session;     // state, one of S_* above    private int state;     // one byte buffer for the update(byte) method, initialized on demand    private byte[] oneByte;     P11Mac(Token token, String algorithm, long mechanism)            throws PKCS11Exception {        super();        this.token = token;        this.algorithm = algorithm;        this.mechanism = mechanism;        Long params = null;        switch ((int)mechanism) {        case (int)CKM_MD5_HMAC:            macLength = 16;            break;        case (int)CKM_SHA_1_HMAC:            macLength = 20;            break;        case (int)CKM_SHA256_HMAC:            macLength = 32;            break;        case (int)CKM_SHA384_HMAC:            macLength = 48;            break;        case (int)CKM_SHA512_HMAC:            macLength = 64;            break;        case (int)CKM_SSL3_MD5_MAC:            macLength = 16;            params = Long.valueOf(16);            break;        case (int)CKM_SSL3_SHA1_MAC:            macLength = 20;            params = Long.valueOf(20);            break;        default:            throw new ProviderException("Unknown mechanism: " + mechanism);        }        ckMechanism = new CK_MECHANISM(mechanism, params);        state = S_UNINIT;        initialize();    }     private void ensureInitialized() throws PKCS11Exception {        token.ensureValid();        if (state == S_UNINIT) {            initialize();        }    }     private void cancelOperation() {        token.ensureValid();        if (state == S_UNINIT) {            return;        }        state = S_UNINIT;        if ((session == null) || (token.explicitCancel == false)) {            return;        }        try {            token.p11.C_SignFinal(session.id(), 0);        } catch (PKCS11Exception e) {            throw new ProviderException("Cancel failed", e);        }    }     private void initialize() throws PKCS11Exception {        if (state == S_RESET) {            return;        }        if (session == null) {            session = token.getOpSession();        }        if (p11Key != null) {            token.p11.C_SignInit                (session.id(), ckMechanism, p11Key.keyID);            state = S_RESET;        } else {            state = S_UNINIT;        }    }     // see JCE spec    protected int engineGetMacLength() {        return macLength;    }     // see JCE spec    protected void engineReset() {        // the framework insists on calling reset() after doFinal(),        // but we prefer to take care of reinitialization ourselves        if (state == S_DOFINAL) {            state = S_UNINIT;            return;        }        cancelOperation();        try {            initialize();        } catch (PKCS11Exception e) {            throw new ProviderException("reset() failed, ", e);        }    }     // see JCE spec    protected void engineInit(Key key, AlgorithmParameterSpec params)            throws InvalidKeyException, InvalidAlgorithmParameterException {        if (params != null) {            throw new InvalidAlgorithmParameterException                ("Parameters not supported");        }        cancelOperation();        p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);        try {            initialize();        } catch (PKCS11Exception e) {            throw new InvalidKeyException("init() failed", e);        }    }     // see JCE spec    protected byte[] engineDoFinal() {        try {            ensureInitialized();            byte[] mac = token.p11.C_SignFinal(session.id(), 0);            state = S_DOFINAL;            return mac;        } catch (PKCS11Exception e) {            throw new ProviderException("doFinal() failed", e);        } finally {            session = token.releaseSession(session);        }    }     // see JCE spec    protected void engineUpdate(byte input) {        if (oneByte == null) {           oneByte = new byte[1];        }        oneByte[0] = input;        engineUpdate(oneByte, 0, 1);    }     // see JCE spec    protected void engineUpdate(byte[] b, int ofs, int len) {        try {            ensureInitialized();            token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);            state = S_UPDATE;        } catch (PKCS11Exception e) {            throw new ProviderException("update() failed", e);        }    }     // see JCE spec    protected void engineUpdate(ByteBuffer byteBuffer) {        try {            ensureInitialized();            int len = byteBuffer.remaining();            if (len <= 0) {                return;            }            if (byteBuffer instanceof DirectBuffer == false) {                super.engineUpdate(byteBuffer);                return;            }            long addr = ((DirectBuffer)byteBuffer).address();            int ofs = byteBuffer.position();            token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len);            byteBuffer.position(ofs + len);            state = S_UPDATE;        } catch (PKCS11Exception e) {            throw new ProviderException("update() failed", e);        }    }}