com.addc.commons.slp.AuthenticationBlock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of addc-slp Show documentation
Show all versions of addc-slp Show documentation
The addc-slp library supplies client classes for registering objects with a Service Location Protocol Daemon and
for looking theses objects up later.
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