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.shared.kerberos.components;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  import java.security.MessageDigest;
26  import java.util.Arrays;
27  
28  import org.apache.directory.api.asn1.Asn1Object;
29  import org.apache.directory.api.asn1.EncoderException;
30  import org.apache.directory.api.asn1.ber.tlv.BerValue;
31  import org.apache.directory.api.asn1.ber.tlv.TLV;
32  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
33  import org.apache.directory.api.util.Strings;
34  import org.apache.directory.server.i18n.I18n;
35  import org.apache.directory.shared.kerberos.KerberosConstants;
36  import org.apache.directory.shared.kerberos.crypto.checksum.ChecksumType;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * The Checksum structure is used to store a checksum associated to a type.
43   * 
44   * The ASN.1 grammar is :
45   * <pre>
46   * Checksum        ::= SEQUENCE {
47   *       cksumtype       [0] Int32,
48   *       checksum        [1] OCTET STRING
49   * }
50   * </pre>
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   */
53  public class Checksum implements Asn1Object
54  {
55      /** The logger */
56      private static final Logger log = LoggerFactory.getLogger( Checksum.class );
57  
58      /** Speedup for logs */
59      private static final boolean IS_DEBUG = log.isDebugEnabled();
60  
61      /** The checksum type used */
62      private ChecksumType cksumtype;
63  
64      /** The byte array containing the checksum */
65      private byte[] checksum;
66  
67      // Storage for computed lengths
68      private int checksumTypeLength;
69      private int checksumBytesLength;
70      private int checksumLength;
71  
72  
73      /**
74       * Creates a new instance of Checksum.
75       */
76      public Checksum()
77      {
78      }
79  
80  
81      /**
82       * Creates a new instance of Checksum.
83       *
84       * @param cksumtype The checksum type used
85       * @param checksum The checksum value
86       */
87      public Checksum( ChecksumType cksumtype, byte[] checksum )
88      {
89          this.cksumtype = cksumtype;
90          this.checksum = checksum;
91      }
92  
93  
94      /**
95       * {@inheritDoc}
96       */
97      @Override
98      public int hashCode()
99      {
100         int hash = 37;
101         hash = hash * 17 + cksumtype.hashCode();
102         hash = hash * 17 + Arrays.hashCode( checksum );
103 
104         return hash;
105     }
106 
107 
108     /**
109      * @see Object#equals(Object)
110      */
111     @Override
112     public boolean equals( Object o )
113     {
114         if ( this == o )
115         {
116             return true;
117         }
118 
119         if ( !( o instanceof Checksum ) )
120         {
121             return false;
122         }
123 
124         Checksum./../../../../../org/apache/directory/shared/kerberos/components/Checksum.html#Checksum">Checksum that = ( Checksum ) o;
125 
126         return ( cksumtype == that.cksumtype ) && ( MessageDigest.isEqual( checksum, that.checksum ) );
127     }
128 
129 
130     /**
131      * Returns the checksum value.
132      *
133      * @return The checksum value.
134      */
135     public byte[] getChecksumValue()
136     {
137         return checksum;
138     }
139 
140 
141     /**
142      * Set the checksum Value.
143      *
144      * @param checksum The checksum value
145      */
146     public void setChecksumValue( byte[] checksum )
147     {
148         this.checksum = checksum;
149     }
150 
151 
152     /**
153      * Returns the {@link ChecksumType}.
154      *
155      * @return The {@link ChecksumType}.
156      */
157     public ChecksumType getChecksumType()
158     {
159         return cksumtype;
160     }
161 
162 
163     /**
164      * Set the {@link ChecksumType}.
165      *
166      * @param cksumType The checksum algorithm used
167      */
168     public void setChecksumType( ChecksumType cksumType )
169     {
170         this.cksumtype = cksumType;
171     }
172 
173 
174     /**
175      * Compute the checksum length
176      * <pre>
177      * Checksum :
178      * 
179      * 0x30 L1 checksum sequence
180      *  |
181      *  +--&gt; 0xA0 L2 cksumtype tag
182      *  |     |
183      *  |     +--&gt; 0x02 L2-1 cksumtype (int)
184      *  |
185      *  +--&gt; 0xA1 L3 checksum tag
186      *        |
187      *        +--&gt; 0x04 L3-1 checksum (OCTET STRING)
188      *        
189      *  where L1 = L2 + lenght(0xA0) + length(L2) +
190      *             L3 + lenght(0xA1) + length(L3) 
191      *  and
192      *  L2 = L2-1 + length(0x02) + length( L2-1) 
193      *  L3 = L3-1 + length(0x04) + length( L3-1) 
194      *  </pre>
195      */
196     public int computeLength()
197     {
198         // Compute the checksulType. The Length will always be contained in 1 byte
199         checksumTypeLength = 1 + 1 + BerValue.getNbBytes( cksumtype.getValue() );
200         checksumLength = 1 + TLV.getNbBytes( checksumTypeLength ) + checksumTypeLength;
201 
202         // Compute the checksum Value
203         if ( checksum == null )
204         {
205             checksumBytesLength = 1 + 1;
206         }
207         else
208         {
209             checksumBytesLength = 1 + TLV.getNbBytes( checksum.length ) + checksum.length;
210         }
211 
212         checksumLength += 1 + TLV.getNbBytes( checksumBytesLength ) + checksumBytesLength;
213 
214         // Compute the whole sequence length
215         return 1 + TLV.getNbBytes( checksumLength ) + checksumLength;
216     }
217 
218 
219     /**
220      * Encode the Checksum message to a PDU. 
221      * 
222      * <pre>
223      * Checksum :
224      * 
225      * 0x30 LL
226      *   0xA0 LL 
227      *     0x02 0x01 cksumtype
228      *   0xA1 LL 
229      *     0x04 LL Checksum
230      * </pre>
231      * @param buffer The buffer where to put the PDU. It should have been allocated
232      * before, with the right size.
233      * @return The constructed PDU.
234      */
235     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
236     {
237         if ( buffer == null )
238         {
239             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
240         }
241 
242         try
243         {
244             // The Checksum SEQ Tag
245             buffer.put( UniversalTag.SEQUENCE.getValue() );
246             buffer.put( TLV.getBytes( checksumLength ) );
247 
248             // The cksumtype, first the tag, then the value
249             buffer.put( ( byte ) KerberosConstants.CHECKSUM_TYPE_TAG );
250             buffer.put( TLV.getBytes( checksumTypeLength ) );
251             BerValue.encode( buffer, cksumtype.getValue() );
252 
253             // The checksum, first the tag, then the value
254             buffer.put( ( byte ) KerberosConstants.CHECKSUM_CHECKSUM_TAG );
255             buffer.put( TLV.getBytes( checksumBytesLength ) );
256             BerValue.encode( buffer, checksum );
257         }
258         catch ( BufferOverflowException boe )
259         {
260             log.error( I18n.err( I18n.ERR_140, 1 + TLV.getNbBytes( checksumLength ) + checksumLength,
261                 buffer.capacity() ) );
262             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
263         }
264 
265         if ( IS_DEBUG )
266         {
267             log.debug( "Checksum encoding : {}", Strings.dumpBytes( buffer.array() ) );
268             log.debug( "Checksum initial value : {}", this );
269         }
270 
271         return buffer;
272     }
273 
274 
275     /**
276      * @see Object#toString()
277      */
278     public String toString()
279     {
280         return toString( "" );
281     }
282 
283 
284     /**
285      * @see Object#toString()
286      */
287     public String toString( String tabs )
288     {
289         StringBuilder sb = new StringBuilder();
290 
291         sb.append( tabs ).append( "Checksum : {\n" );
292         sb.append( tabs ).append( "    cksumtype: " ).append( cksumtype ).append( '\n' );
293 
294         if ( checksum != null )
295         {
296             sb.append( tabs + "    checksum:" ).append( Strings.dumpBytes( checksum ) ).append( '\n' );
297         }
298 
299         sb.append( tabs + "}\n" );
300 
301         return sb.toString();
302     }
303 }