View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.shared.messages.value;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.util.Arrays;
26  
27  import org.apache.directory.server.kerberos.shared.crypto.checksum.ChecksumType;
28  import org.apache.directory.shared.asn1.AbstractAsn1Object;
29  import org.apache.directory.shared.asn1.ber.tlv.TLV;
30  import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
31  import org.apache.directory.shared.asn1.ber.tlv.Value;
32  import org.apache.directory.shared.asn1.codec.EncoderException;
33  import org.apache.directory.shared.ldap.util.StringTools;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  
38  /**
39   * The Checksum structure is used to store a checksum associated to a type.
40   * 
41   * The ASN.1 grammar is :
42   * Checksum        ::= SEQUENCE {
43   *       cksumtype       [0] Int32,
44   *       checksum        [1] OCTET STRING
45   * }
46   * 
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   * @version $Rev: 642496 $, $Date: 2008-03-29 04:09:22 +0100 (Sa, 29 Mär 2008) $
49   */
50  public class Checksum extends AbstractAsn1Object
51  {
52      /** The logger */
53      private static final Logger log = LoggerFactory.getLogger( Checksum.class );
54  
55      /** Speedup for logs */
56      private static final boolean IS_DEBUG = log.isDebugEnabled();
57  
58      /** The checksum type used */
59      private ChecksumType cksumtype;
60  
61      /** The byte array containing the checksum */
62      private byte[] checksum;
63  
64      // Storage for computed lengths
65      private transient int checksumTypeLength;
66      private transient int checksumBytesLength;
67      private transient int checksumLength;
68  
69  
70      /**
71       * Creates a new instance of Checksum.
72       */
73      public Checksum()
74      {
75      }
76  
77      
78      /**
79       * Creates a new instance of Checksum.
80       *
81       * @param cksumtype The checksum type used
82       * @param checksum The checksum value
83       */
84      public Checksum( ChecksumType cksumtype, byte[] checksum )
85      {
86          this.cksumtype = cksumtype;
87          this.checksum = checksum;
88      }
89  
90  
91      /**
92       * @see Object#equals(Object)
93       */
94      public boolean equals( Object o )
95      {
96          if ( this == o )
97          {
98              return true;
99          }
100 
101         if ( !( o instanceof Checksum ) )
102         {
103             return false;
104         }
105 
106         Checksum that = ( Checksum ) o;
107 
108         return ( cksumtype == that.cksumtype ) && ( Arrays.equals( checksum, that.checksum ) );
109     }
110 
111 
112     /**
113      * Returns the checksum value.
114      *
115      * @return The checksum value.
116      */
117     public byte[] getChecksumValue()
118     {
119         return checksum;
120     }
121 
122 
123     /**
124      * Set the checksum Value.
125      *
126      * @param checksum The checksum value
127      */
128     public void setChecksumValue( byte[] checksum )
129     {
130         this.checksum = checksum;
131     }
132 
133 
134     /**
135      * Returns the {@link ChecksumType}.
136      *
137      * @return The {@link ChecksumType}.
138      */
139     public ChecksumType getChecksumType()
140     {
141         return cksumtype;
142     }
143 
144 
145     /**
146      * Set the {@link ChecksumType}.
147      *
148      * @param cksumType The checksum algorithm used
149      */
150     public void setChecksumType( ChecksumType cksumType )
151     {
152         this.cksumtype = cksumType;
153     }
154 
155 
156     /**
157      * Compute the checksum length
158      * 
159      * Checksum :
160      * 
161      * 0x30 L1 checksum sequence
162      *  |
163      *  +--> 0xA0 L2 cksumtype tag
164      *  |     |
165      *  |     +--> 0x02 L2-1 cksumtype (int)
166      *  |
167      *  +--> 0xA1 L3 checksum tag
168      *        |
169      *        +--> 0x04 L3-1 checksum (OCTET STRING)
170      *        
171      *  where L1 = L2 + lenght(0xA0) + length(L2) +
172      *             L3 + lenght(0xA1) + length(L3) 
173      *  and
174      *  L2 = L2-1 + length(0x02) + length( L2-1) 
175      *  L3 = L3-1 + length(0x04) + length( L3-1) 
176      */
177     public int computeLength()
178     {
179         // Compute the checksulType. The Length will always be contained in 1 byte
180         checksumTypeLength = 1 + 1 + Value.getNbBytes( cksumtype.getOrdinal() );
181         checksumLength = 1 + TLV.getNbBytes( checksumTypeLength ) + checksumTypeLength;
182 
183         // Compute the checksum Value
184         if ( checksum == null )
185         {
186             checksumBytesLength = 1 + 1;
187         }
188         else
189         {
190             checksumBytesLength = 1 + TLV.getNbBytes( checksum.length ) + checksum.length;
191         }
192 
193         checksumLength += 1 + TLV.getNbBytes( checksumBytesLength ) + checksumBytesLength;
194 
195         // Compute the whole sequence length
196         int checksumSeqLength = 1 + Value.getNbBytes( checksumLength ) + checksumLength;
197 
198         return checksumSeqLength;
199 
200     }
201 
202 
203     /**
204      * Encode the Checksum message to a PDU. 
205      * 
206      * Checksum :
207      * 
208      * 0x30 LL
209      *   0xA0 LL 
210      *     0x02 0x01 cksumtype
211      *   0xA1 LL 
212      *     0x04 LL Checksum
213      * 
214      * @param buffer The buffer where to put the PDU. It should have been allocated
215      * before, with the right size.
216      * @return The constructed PDU.
217      */
218     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
219     {
220         if ( buffer == null )
221         {
222             throw new EncoderException( "Cannot put a PDU in a null buffer !" );
223         }
224 
225         try
226         {
227             // The Checksum SEQ Tag
228             buffer.put( UniversalTag.SEQUENCE_TAG );
229             buffer.put( TLV.getBytes( checksumLength ) );
230 
231             // The cksumtype, first the tag, then the value
232             buffer.put( ( byte ) 0xA0 );
233             buffer.put( TLV.getBytes( checksumTypeLength ) );
234             Value.encode( buffer, cksumtype.getOrdinal() );
235 
236             // The checksum, first the tag, then the value
237             buffer.put( ( byte ) 0xA1 );
238             buffer.put( TLV.getBytes( checksumBytesLength ) );
239             Value.encode( buffer, checksum );
240         }
241         catch ( BufferOverflowException boe )
242         {
243             log.error( "Cannot encode the Checksum object, the PDU size is {} when only {} bytes has been allocated", 1
244                 + TLV.getNbBytes( checksumLength ) + checksumLength, buffer.capacity() );
245             throw new EncoderException( "The PDU buffer size is too small !" );
246         }
247 
248         if ( IS_DEBUG )
249         {
250             log.debug( "Checksum encoding : {}", StringTools.dumpBytes( buffer.array() ) );
251             log.debug( "Checksum initial value : {}", toString() );
252         }
253 
254         return buffer;
255     }
256 
257     /**
258      * @see Object#toString()
259      */
260     public String toString()
261     {
262         return toString( "" );
263     }
264 
265 
266     /**
267      * @see Object#toString()
268      */
269     public String toString( String tabs )
270     {
271         StringBuilder sb = new StringBuilder();
272 
273         sb.append( tabs ).append( "Checksum : {\n" );
274         sb.append( tabs ).append( "    cksumtype: " ).append(  cksumtype ).append( '\n' );
275 
276         if ( checksum != null )
277         {
278             sb.append( tabs + "    checksum:" ).append( StringTools.dumpBytes( checksum ) ).append( '\n' );
279         }
280 
281         sb.append( tabs + "}\n" );
282 
283         return sb.toString();
284     }
285 }