package org.limewire.security; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; /**<p> * Implements a security token that can write itself to * an output stream and queries for its validity. * </p><p> * Subclasses must implement * {@link #getFromMAC(byte[], org.limewire.security.SecurityToken.TokenData)}. * <code>getFromMAC</code> returns the payload of * the security token as it will appear on the network. * </p><p> * See message authentication code, <a * href="http://en.wikipedia.org/wiki/Message_authentication_code">MAC</a>, for * more information. </p> */ public abstract class AbstractSecurityToken implements SecurityToken { private final MACCalculatorRepositoryManager mgr; /** * The encrypted data. */ private final byte[] _securityToken; protected AbstractSecurityToken(TokenData data, MACCalculatorRepositoryManager mgr) { this.mgr = mgr; _securityToken = getFromMAC(mgr.getMACBytes(data), data); } protected AbstractSecurityToken(byte [] network, MACCalculatorRepositoryManager mgr) throws InvalidSecurityTokenException { this.mgr = mgr; if (!isValidBytes(network)) { throw new InvalidSecurityTokenException("invalid data: " + Arrays.toString(network)); } _securityToken = network; } public final boolean isFor(TokenData data) { if(!isValidTokenData(data)) { return false; } Iterable<byte[]> tokens = mgr.getAllBytes(data); for (byte[] token : tokens) { if (Arrays.equals(_securityToken, getFromMAC(token, data))) { return true; } } return false; } /** * Determines if the given <code>TokenData</code> is valid for this * <code>SecurityToken</code>. By default, all <code>TokenData</code>s are * valid. */ protected boolean isValidTokenData(TokenData data) { return true; } public final void write(OutputStream os) throws IOException { os.write(_securityToken); } public final byte[] getBytes() { byte[] copy = new byte[_securityToken.length]; System.arraycopy(_securityToken, 0, copy, 0, _securityToken.length); return copy; } /** * @param MAC the calculated cryptographic MAC * @param data the <tt>TokenData</tt> this security token is created from. * @return the payload of this security token as it will appear on the network */ protected abstract byte [] getFromMAC(byte [] MAC, TokenData data); /** * Determines if the given data bytes are valid. * By default, all non-null and non-empty bytes are valid. */ protected boolean isValidBytes(byte[] network) { return network != null && network.length > 0; } /** * Should not be used if it is possible to call * {@link #isFor(org.limewire.security.SecurityToken.TokenData)} which * takes all possible {@link MACCalculatorRepository MACCalculatorRepositories} * into account. */ @Override public boolean equals(Object obj) { if (obj instanceof SecurityToken) { SecurityToken t = (SecurityToken)obj; return Arrays.equals(_securityToken, t.getBytes()); } return false; } @Override public int hashCode() { return Arrays.hashCode(_securityToken); } }