All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.addc.commons.slp.AuthenticationBlock Maven / Gradle / Ivy

Go to download

The addc-slp library supplies client classes for registering objects with a Service Location Protocol Daemon and for looking theses objects up later.

There is a newer version: 2.6
Show newest version
package com.addc.commons.slp;

import java.io.DataInput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.addc.commons.Constants;
import com.addc.commons.slp.configuration.SLPConfig;

/**
 * Implementation of the SLP Authentication Block.
 */
public class AuthenticationBlock {
    private static final Logger LOGGER= LoggerFactory.getLogger(AuthenticationBlock.class);
    private int timestamp;
    private byte[] data;
    private SLPConfig config;
    private byte[] sig;
    private String spi;

    /**
     * Read a block from a Data Input.
     *
     * @param config The configuration to use
     * @param dataIn
     *            The data input.
     * @return The authentication block
     * @throws IOException If there is I/O error
     */
    public static AuthenticationBlock readBlock(SLPConfig config, DataInput dataIn) throws IOException {
        AuthenticationBlock block= new AuthenticationBlock(config);
        dataIn.readShort();
        int size= dataIn.readShort() & 0xFFFF;
        block.timestamp= dataIn.readInt();
        int spilen= dataIn.readShort() & 0xFFFF;
        byte[] spibytes= new byte[spilen];
        dataIn.readFully(spibytes);
        block.spi= new String(spibytes, Constants.UTF8);
        block.sig= new byte[size - (spilen + 10)];
        dataIn.readFully(block.sig);
        return block;
    }

    /**
     * Create a new AuthenticationBlock
     * 
     * @param config
     *            The configuration to use
     * @param bsd
     *            The BSD
     * @param spIndex
     *            The Security Parameter Index
     * @param timestamp
     *            The timestamp
     * @param data
     *            The data
     * @throws ServiceLocationException If the BSD is not 2 (DSA)
     */
    public AuthenticationBlock(SLPConfig config, int bsd, String spIndex, int timestamp, byte[] data)
            throws ServiceLocationException {
        this(config);
        if (bsd != 0x0002) {
            LOGGER.warn("Only BSD 0x0002 (DSA) is supported.");
            throw new ServiceLocationException("Only BSD 0x0002 (DSA) is supported.", SLPConstants.NOT_IMPLEMENTED);
        }
        int tlimit= (int) ((System.currentTimeMillis()) / 1000);
        if (timestamp <= tlimit) {
            LOGGER.warn("Invalid timestamp, it must be in the future.");
            throw new ServiceLocationException("Invalid timestamp, it must be in the future.", SLPConstants.NOT_IMPLEMENTED);
        }
        this.timestamp= timestamp;
        if (data == null) {
            this.data= new byte[0];
        } else {
            this.data= Arrays.copyOf(data, data.length);
        }

        this.spi= spIndex;

        sign();
    }

    /**
     * Get the SPI.
     * 
     * @return the SPI.
     */
    String getSPI() {
        return spi;
    }

    /**
     * Get the timestamp.
     * 
     * @return the timestamp.
     */
    int getTimestamp() {
        return timestamp;
    }

    /**
     * Get the signature
     *
     * @return the signature
     */
    byte[] getSignature() {
        return Arrays.copyOf(sig, sig.length);
    }
    
    /**
     * Verify the data
     * 
     * @param data
     *            The data to verify
     * @return true is valid.
     * @throws ServiceLocationException
     *             If authentication fails.
     */
    boolean verify(byte[] authData) throws ServiceLocationException {
        try {
            Signature signature= Signature.getInstance("SHA1withDSA");
            signature.initVerify(config.getPublicKey(spi));
            signature.update(authData);
            return signature.verify(sig);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            LOGGER.error("Could not verify data with SPI: {}", spi, e);
            throw new ServiceLocationException("Could not verify data with SPI: " + spi, e,
                    SLPConstants.AUTHENTICATION_FAILED);
        }
    }

    /**
     * Calculate the block size.
     * 
     * @return the block size.
     */
    public int calcSize() {
        return 10 + spi.length() + sig.length;
    }

    /**
     * Write the block to the SLPD
     * 
     * @param out
     *            The data out
     * @throws IOException
     *             If the data cannot be written.
     */
    public void writeBlock(DataOutputStream out) throws IOException {
        out.writeShort(0x0002); // BSD
        out.writeShort(calcSize());
        out.writeInt(timestamp);

        out.writeUTF(spi);
        out.write(sig);
    }

    @Override
    public int hashCode() {
        final int prime= 31;
        int result= 1;
        result= prime * Arrays.hashCode(sig);
        result= prime * result + spi.hashCode();
        result= prime * result + timestamp;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof AuthenticationBlock)) {
            return false;
        }
        AuthenticationBlock other= (AuthenticationBlock) obj;
        return (Arrays.equals(sig, other.sig) && spi.equals(other.spi)
                && (timestamp == other.timestamp));
    }

    @Override
    public String toString() {
        StringBuilder builder= new StringBuilder();
        builder.append("AuthenticationBlock [timestamp=");
        builder.append(timestamp);
        builder.append(", spi=");
        builder.append(spi);
        builder.append(']');
        return builder.toString();
    }

    private void sign() throws ServiceLocationException {
        try {
            PrivateKey privateKey= config.getPrivateKey(spi);
            Signature signature= Signature.getInstance("SHA1withDSA");
            signature.initSign(privateKey);
            signature.update(data);
            sig= signature.sign();
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | IOException e) {
            LOGGER.error("Failed to sign authentication block", e);
            throw new ServiceLocationException("Could not sign data", e, SLPConstants.AUTHENTICATION_FAILED);
        }
    }

    private AuthenticationBlock(SLPConfig config) {
        this.config= config;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy