001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.kerberos.shared.messages.value; 021 022 023 import java.nio.BufferOverflowException; 024 import java.nio.ByteBuffer; 025 import java.util.Arrays; 026 027 import org.apache.directory.server.i18n.I18n; 028 import org.apache.directory.server.kerberos.shared.crypto.checksum.ChecksumType; 029 import org.apache.directory.shared.asn1.AbstractAsn1Object; 030 import org.apache.directory.shared.asn1.ber.tlv.TLV; 031 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 032 import org.apache.directory.shared.asn1.ber.tlv.Value; 033 import org.apache.directory.shared.asn1.codec.EncoderException; 034 import org.apache.directory.shared.ldap.util.StringTools; 035 import org.slf4j.Logger; 036 import org.slf4j.LoggerFactory; 037 038 039 /** 040 * The Checksum structure is used to store a checksum associated to a type. 041 * 042 * The ASN.1 grammar is : 043 * Checksum ::= SEQUENCE { 044 * cksumtype [0] Int32, 045 * checksum [1] OCTET STRING 046 * } 047 * 048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 049 * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $ 050 */ 051 public class Checksum extends AbstractAsn1Object 052 { 053 /** The logger */ 054 private static final Logger log = LoggerFactory.getLogger( Checksum.class ); 055 056 /** Speedup for logs */ 057 private static final boolean IS_DEBUG = log.isDebugEnabled(); 058 059 /** The checksum type used */ 060 private ChecksumType cksumtype; 061 062 /** The byte array containing the checksum */ 063 private byte[] checksum; 064 065 // Storage for computed lengths 066 private transient int checksumTypeLength; 067 private transient int checksumBytesLength; 068 private transient int checksumLength; 069 070 071 /** 072 * Creates a new instance of Checksum. 073 */ 074 public Checksum() 075 { 076 } 077 078 079 /** 080 * Creates a new instance of Checksum. 081 * 082 * @param cksumtype The checksum type used 083 * @param checksum The checksum value 084 */ 085 public Checksum( ChecksumType cksumtype, byte[] checksum ) 086 { 087 this.cksumtype = cksumtype; 088 this.checksum = checksum; 089 } 090 091 092 /** 093 * @see Object#equals(Object) 094 */ 095 public boolean equals( Object o ) 096 { 097 if ( this == o ) 098 { 099 return true; 100 } 101 102 if ( !( o instanceof Checksum ) ) 103 { 104 return false; 105 } 106 107 Checksum that = ( Checksum ) o; 108 109 return ( cksumtype == that.cksumtype ) && ( Arrays.equals( checksum, that.checksum ) ); 110 } 111 112 113 /** 114 * Returns the checksum value. 115 * 116 * @return The checksum value. 117 */ 118 public byte[] getChecksumValue() 119 { 120 return checksum; 121 } 122 123 124 /** 125 * Set the checksum Value. 126 * 127 * @param checksum The checksum value 128 */ 129 public void setChecksumValue( byte[] checksum ) 130 { 131 this.checksum = checksum; 132 } 133 134 135 /** 136 * Returns the {@link ChecksumType}. 137 * 138 * @return The {@link ChecksumType}. 139 */ 140 public ChecksumType getChecksumType() 141 { 142 return cksumtype; 143 } 144 145 146 /** 147 * Set the {@link ChecksumType}. 148 * 149 * @param cksumType The checksum algorithm used 150 */ 151 public void setChecksumType( ChecksumType cksumType ) 152 { 153 this.cksumtype = cksumType; 154 } 155 156 157 /** 158 * Compute the checksum length 159 * 160 * Checksum : 161 * 162 * 0x30 L1 checksum sequence 163 * | 164 * +--> 0xA0 L2 cksumtype tag 165 * | | 166 * | +--> 0x02 L2-1 cksumtype (int) 167 * | 168 * +--> 0xA1 L3 checksum tag 169 * | 170 * +--> 0x04 L3-1 checksum (OCTET STRING) 171 * 172 * where L1 = L2 + lenght(0xA0) + length(L2) + 173 * L3 + lenght(0xA1) + length(L3) 174 * and 175 * L2 = L2-1 + length(0x02) + length( L2-1) 176 * L3 = L3-1 + length(0x04) + length( L3-1) 177 */ 178 public int computeLength() 179 { 180 // Compute the checksulType. The Length will always be contained in 1 byte 181 checksumTypeLength = 1 + 1 + Value.getNbBytes( cksumtype.getOrdinal() ); 182 checksumLength = 1 + TLV.getNbBytes( checksumTypeLength ) + checksumTypeLength; 183 184 // Compute the checksum Value 185 if ( checksum == null ) 186 { 187 checksumBytesLength = 1 + 1; 188 } 189 else 190 { 191 checksumBytesLength = 1 + TLV.getNbBytes( checksum.length ) + checksum.length; 192 } 193 194 checksumLength += 1 + TLV.getNbBytes( checksumBytesLength ) + checksumBytesLength; 195 196 // Compute the whole sequence length 197 int checksumSeqLength = 1 + Value.getNbBytes( checksumLength ) + checksumLength; 198 199 return checksumSeqLength; 200 201 } 202 203 204 /** 205 * Encode the Checksum message to a PDU. 206 * 207 * Checksum : 208 * 209 * 0x30 LL 210 * 0xA0 LL 211 * 0x02 0x01 cksumtype 212 * 0xA1 LL 213 * 0x04 LL Checksum 214 * 215 * @param buffer The buffer where to put the PDU. It should have been allocated 216 * before, with the right size. 217 * @return The constructed PDU. 218 */ 219 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 220 { 221 if ( buffer == null ) 222 { 223 throw new EncoderException( I18n.err( I18n.ERR_148 ) ); 224 } 225 226 try 227 { 228 // The Checksum SEQ Tag 229 buffer.put( UniversalTag.SEQUENCE_TAG ); 230 buffer.put( TLV.getBytes( checksumLength ) ); 231 232 // The cksumtype, first the tag, then the value 233 buffer.put( ( byte ) 0xA0 ); 234 buffer.put( TLV.getBytes( checksumTypeLength ) ); 235 Value.encode( buffer, cksumtype.getOrdinal() ); 236 237 // The checksum, first the tag, then the value 238 buffer.put( ( byte ) 0xA1 ); 239 buffer.put( TLV.getBytes( checksumBytesLength ) ); 240 Value.encode( buffer, checksum ); 241 } 242 catch ( BufferOverflowException boe ) 243 { 244 log.error( I18n.err( I18n.ERR_140, 1 + TLV.getNbBytes( checksumLength ) + checksumLength, 245 buffer.capacity() ) ); 246 throw new EncoderException( I18n.err( I18n.ERR_138 ) ); 247 } 248 249 if ( IS_DEBUG ) 250 { 251 log.debug( "Checksum encoding : {}", StringTools.dumpBytes( buffer.array() ) ); 252 log.debug( "Checksum initial value : {}", toString() ); 253 } 254 255 return buffer; 256 } 257 258 /** 259 * @see Object#toString() 260 */ 261 public String toString() 262 { 263 return toString( "" ); 264 } 265 266 267 /** 268 * @see Object#toString() 269 */ 270 public String toString( String tabs ) 271 { 272 StringBuilder sb = new StringBuilder(); 273 274 sb.append( tabs ).append( "Checksum : {\n" ); 275 sb.append( tabs ).append( " cksumtype: " ).append( cksumtype ).append( '\n' ); 276 277 if ( checksum != null ) 278 { 279 sb.append( tabs + " checksum:" ).append( StringTools.dumpBytes( checksum ) ).append( '\n' ); 280 } 281 282 sb.append( tabs + "}\n" ); 283 284 return sb.toString(); 285 } 286 }