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

org.ice4j.attribute.FingerprintAttribute Maven / Gradle / Ivy

There is a newer version: 3.2-4-g1373788
Show newest version
/*
 * ice4j, the OpenSource Java Solution for NAT and Firewall Traversal.
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ice4j.attribute;

import java.util.zip.*;

import org.ice4j.*;
import org.ice4j.stack.*;

/**
 * The FINGERPRINT attribute is used to distinguish STUN packets from packets
 * of other protocols. It MAY be present in all STUN messages.  The
 * value of the attribute is computed as the CRC-32 of the STUN message
 * up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
 * the 32-bit value 0x5354554e (the XOR helps in cases where an
 * application packet is also using CRC-32 in it).  The 32-bit CRC is
 * the one defined in ITU V.42 [ITU.V42.2002], which has a generator
 * polynomial of x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1.
 * When present, the FINGERPRINT attribute MUST be the last attribute in
 * the message, and thus will appear after MESSAGE-INTEGRITY.
 * 

* The FINGERPRINT attribute can aid in distinguishing STUN packets from * packets of other protocols. See Section 8. *

* As with MESSAGE-INTEGRITY, the CRC used in the FINGERPRINT attribute * covers the length field from the STUN message header. Therefore, * this value must be correct and include the CRC attribute as part of * the message length, prior to computation of the CRC. When using the * FINGERPRINT attribute in a message, the attribute is first placed * into the message with a dummy value, then the CRC is computed, and * then the value of the attribute is updated. If the MESSAGE-INTEGRITY * attribute is also present, then it must be present with the correct * message-integrity value before the CRC is computed, since the CRC is * done over the value of the MESSAGE-INTEGRITY attribute as well. * * @author Sebastien Vincent * @author Emil Ivov */ public class FingerprintAttribute extends Attribute implements ContentDependentAttribute { /** * Attribute name. */ public static final String NAME = "FINGERPRINT"; /** * The value that we need to XOR the CRC with. The XOR helps in cases where * an application packet is also using CRC-32 in it). */ public static final byte[] XOR_MASK = { 0x53, 0x54, 0x55, 0x4e}; /** * The CRC32 checksum that this attribute is carrying. Only used in incoming * messages. */ private byte[] crc; /** * Creates a FingerPrintAttribute instance. */ FingerprintAttribute() { super(FINGERPRINT); } /** * Returns the CRC32 checksum that this attribute is carrying. Only makes * sense for incoming messages and hence only set for them. * * @return the CRC32 checksum that this attribute is carrying or * null if it has not been set. */ public byte[] getChecksum() { return crc; } /** * Returns the length of this attribute's body. * * @return the length of this attribute's value. */ public char getDataLength() { return 4; } /** * Returns the human readable name of this attribute. * * @return this attribute's name. */ public String getName() { return NAME; } /** * Compares two STUN Attributes. Two attributes are considered equal when * they have the same type length and value. * * @param obj the object to compare this attribute with. * * @return true if the attributes are equal and false otherwise. */ public boolean equals(Object obj) { if (! (obj instanceof FingerprintAttribute)) return false; if (obj == this) return true; FingerprintAttribute att = (FingerprintAttribute) obj; if (att.getAttributeType() != getAttributeType() || att.getDataLength() != getDataLength()) { return false; } return true; } /** * Returns a binary representation of this attribute. * * @return nothing * @throws UnsupportedOperationException since {@link * ContentDependentAttribute}s should be encoded through the content * dependent encode method. */ public byte[] encode() throws UnsupportedOperationException { throw new UnsupportedOperationException( "ContentDependentAttributes should be encoded " + "through the contend-dependent encode method"); } /** * Returns a binary representation of this attribute. * * @param stunStack the StunStack in the context of which the * request to encode this ContentDependentAttribute is being made * @param content the content of the message that this attribute will be * transported in * @param offset the content-related offset where the actual * content starts. * @param length the length of the content in the content array. * * @return a binary representation of this attribute valid for the message * with the specified content. */ public byte[] encode( StunStack stunStack, byte[] content, int offset, int length) { char type = getAttributeType(); byte binValue[] = new byte[HEADER_LENGTH + getDataLength()]; //Type binValue[0] = (byte)(type >> 8); binValue[1] = (byte)(type & 0x00FF); //Length binValue[2] = (byte)(getDataLength() >> 8); binValue[3] = (byte)(getDataLength() & 0x00FF); //calculate the check sum byte[] xorCrc32 = calculateXorCRC32(content, offset, length); //copy into the attribute; binValue[4] = xorCrc32[0]; binValue[5] = xorCrc32[1]; binValue[6] = xorCrc32[2]; binValue[7] = xorCrc32[3]; return binValue; } /** * Sets this attribute's fields according to the message and attributeValue * arrays. * * @param attributeValue a binary array containing this attribute's field * values and NOT containing the attribute header. * @param offset the position where attribute values begin (most often * offset is equal to the index of the first byte after length) * @param length the length of the binary array. * the start of this attribute. * * @throws StunException if attrubteValue contains invalid data. */ public void decodeAttributeBody( byte[] attributeValue, char offset, char length) throws StunException { if (length != 4) { throw new StunException("length invalid"); } byte[] incomingCrcBytes = new byte[4]; incomingCrcBytes[0] = attributeValue[offset]; incomingCrcBytes[1] = attributeValue[offset + 1]; incomingCrcBytes[2] = attributeValue[offset + 2]; incomingCrcBytes[3] = attributeValue[offset + 3]; this.crc = incomingCrcBytes; } /** * Calculates and returns the CRC32 checksum for message after * applying the XOR_MASK specified by RFC 5389. * * @param message the message whose checksum we'd like to have * @param offset the location in message where the actual message * starts. * @param len the number of message bytes in message * * @return the CRC value that should be sent in a FINGERPRINT * attribute traveling in the message message. */ public static byte[] calculateXorCRC32(byte[] message, int offset, int len) { //now check whether the CRC really is what it's supposed to be. //re calculate the check sum CRC32 checksum = new CRC32(); checksum.update(message, offset, len); long crc = checksum.getValue(); byte[] xorCRC32 = new byte[4]; xorCRC32[0] = (byte)((byte)((crc >> 24) & 0xff) ^ XOR_MASK[0]); xorCRC32[1] = (byte)((byte)((crc >> 16) & 0xff) ^ XOR_MASK[1]); xorCRC32[2] = (byte)((byte)((crc >> 8) & 0xff) ^ XOR_MASK[2]); xorCRC32[3] = (byte)((byte) (crc & 0xff) ^ XOR_MASK[3]); return xorCRC32; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy