    001    // Copyright 2012 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.util;
    016
    017    import org.apache.commons.codec.binary.Base64;
    018    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    019
    020    import javax.crypto.Mac;
    021    import java.io.IOException;
    022    import java.io.OutputStream;
    023    import java.security.Key;
    024
    025    /**
    026     * An output stream that wraps around a {@link Mac} (message authentication code algorithm).  This is currently
    027     * used for symmetric (private) keys, but in theory could be used with assymetric (public/private) keys.
    028     *
    029     * @since 5.3.6
    030     */
    031    public class MacOutputStream extends OutputStream
    032    {
    033        private final Mac mac;
    034
    035        public static MacOutputStream streamFor(Key key) throws IOException
    036        {
    037            try
    038            {
    039                Mac mac = Mac.getInstance(key.getAlgorithm());
    040                mac.init(key);
    041
    042                return new MacOutputStream(mac);
    043            } catch (Exception ex)
    044            {
    045                throw new IOException("Unable to create MacOutputStream: " + InternalUtils.toMessage(ex));
    046            }
    047        }
    048
    049        public MacOutputStream(Mac mac)
    050        {
    051            assert mac != null;
    052
    053            this.mac = mac;
    054        }
    055
    056        /**
    057         * Should only be invoked once, immediately after this stream is closed; it generates the final MAC result, and
    058         * returns it as a Base64 encoded string.
    059         *
    060         * @return Base64 encoded MAC result
    061         */
    062        public String getResult()
    063        {
    064            byte[] result = mac.doFinal();
    065
    066            return new String(Base64.encodeBase64(result));
    067        }
    068
    069        @Override
    070        public void write(int b) throws IOException
    071        {
    072            mac.update((byte) b);
    073        }
    074
    075        @Override
    076        public void write(byte[] b) throws IOException
    077        {
    078            mac.update(b);
    079        }
    080
    081        @Override
    082        public void write(byte[] b, int off, int len) throws IOException
    083        {
    084            mac.update(b, off, len);
    085        }
    086    }