view src/com/trilead/ssh2/crypto/digest/MAC.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children
line wrap: on
line source


package com.trilead.ssh2.crypto.digest;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;

/**
 * MAC.
 *
 * @author Christian Plattner, plattner@trilead.com
 * @version $Id: MAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 */
public final class MAC {
    /**
     * From http://tools.ietf.org/html/rfc4253
     */
    private static final String HMAC_MD5 = "hmac-md5";

    /**
     * From http://tools.ietf.org/html/rfc4253
     */
    private static final String HMAC_MD5_96 = "hmac-md5-96";

    /**
     * From http://tools.ietf.org/html/rfc4253
     */
    private static final String HMAC_SHA1 = "hmac-sha1";

    /**
     * From http://tools.ietf.org/html/rfc4253
     */
    private static final String HMAC_SHA1_96 = "hmac-sha1-96";

    /**
     * From http://tools.ietf.org/html/rfc6668
     */
    private static final String HMAC_SHA2_256 = "hmac-sha2-256";

    /**
     * From http://tools.ietf.org/html/rfc6668
     */
    private static final String HMAC_SHA2_512 = "hmac-sha2-512";

    Mac mac;
    int outSize;
    int macSize;
    byte[] buffer;

    /* Higher Priority First */
    private static final String[] MAC_LIST = {
        HMAC_SHA2_256, HMAC_SHA2_512,
        HMAC_SHA1_96, HMAC_SHA1, HMAC_MD5_96, HMAC_MD5
    };

    public final static String[] getMacList() {
        return MAC_LIST;
    }

    public final static void checkMacList(String[] macs) {
        for (int i = 0; i < macs.length; i++)
            getKeyLen(macs[i]);
    }

    public final static int getKeyLen(String type) {
        if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type))
            return 20;

        if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type))
            return 16;

        if (HMAC_SHA2_256.equals(type))
            return 32;

        if (HMAC_SHA2_512.equals(type))
            return 64;

        throw new IllegalArgumentException("Unkown algorithm " + type);
    }

    public MAC(String type, byte[] key) {
        try {
            if (HMAC_SHA1.equals(type) || HMAC_SHA1_96.equals(type)) {
                mac = Mac.getInstance("HmacSHA1");
            }
            else if (HMAC_MD5.equals(type) || HMAC_MD5_96.equals(type)) {
                mac = Mac.getInstance("HmacMD5");
            }
            else if (HMAC_SHA2_256.equals(type)) {
                mac = Mac.getInstance("HmacSHA256");
            }
            else if (HMAC_SHA2_512.equals(type)) {
                mac = Mac.getInstance("HmacSHA512");
            }
            else
                throw new IllegalArgumentException("Unkown algorithm " + type);
        }
        catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("Unknown algorithm " + type, e);
        }

        macSize = mac.getMacLength();

        if (type.endsWith("-96")) {
            outSize = 12;
            buffer = new byte[macSize];
        }
        else {
            outSize = macSize;
            buffer = null;
        }

        try {
            mac.init(new SecretKeySpec(key, type));
        }
        catch (InvalidKeyException e) {
            throw new IllegalArgumentException(e);
        }
    }

    public final void initMac(int seq) {
        mac.reset();
        mac.update((byte)(seq >> 24));
        mac.update((byte)(seq >> 16));
        mac.update((byte)(seq >> 8));
        mac.update((byte)(seq));
    }

    public final void update(byte[] packetdata, int off, int len) {
        mac.update(packetdata, off, len);
    }

    public final void getMac(byte[] out, int off) {
        try {
            if (buffer != null) {
                mac.doFinal(buffer, 0);
                System.arraycopy(buffer, 0, out, off, out.length - off);
            }
            else {
                mac.doFinal(out, off);
            }
        }
        catch (ShortBufferException e) {
            throw new IllegalStateException(e);
        }
    }

    public final int size() {
        return outSize;
    }
}