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  package org.apache.maven.shared.repository.utils;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.security.MessageDigest;
26  import java.security.NoSuchAlgorithmException;
27  import java.util.regex.Matcher;
28  import java.util.regex.Pattern;
29  
30  import org.codehaus.plexus.util.IOUtil;
31  
32  /**
33   * Create a digest for a file. Stolen from repository-utils - once released, use that instead.
34   *
35   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
36   * @todo [jdcasey] This needs unit tests.
37   */
38  public final class DigestUtils
39  {
40      private static final int CHECKSUM_BUFFER_SIZE = 16384;
41  
42      private static final int BYTE_MASK = 0xFF;
43  
44      private DigestUtils()
45      {
46      }
47  
48      public static String createChecksum( File file, String algorithm )
49          throws IOException, NoSuchAlgorithmException
50      {
51          MessageDigest digest = MessageDigest.getInstance( algorithm );
52  
53          InputStream fis = new FileInputStream( file );
54          try
55          {
56              byte[] buffer = new byte[CHECKSUM_BUFFER_SIZE];
57              int numRead;
58              do
59              {
60                  numRead = fis.read( buffer );
61                  if ( numRead > 0 )
62                  {
63                      digest.update( buffer, 0, numRead );
64                  }
65              }
66              while ( numRead != -1 );
67          }
68          finally
69          {
70              IOUtil.close( fis );
71          }
72  
73          return byteArrayToHexStr( digest.digest() );
74      }
75  
76      public boolean verifyChecksum( File file, String checksum, String algorithm )
77          throws NoSuchAlgorithmException, IOException
78      {
79          boolean result = true;
80  
81          String trimmedChecksum = checksum.replace( '\n', ' ' ).trim();
82          // Free-BSD / openssl
83          Matcher m = Pattern.compile( algorithm.replaceAll( "-", "" ) + "\\s*\\((.*?)\\)\\s*=\\s*([a-zA-Z0-9]+)" )
84              .matcher( trimmedChecksum );
85          if ( m.matches() )
86          {
87              String filename = m.group( 1 );
88              if ( !filename.equals( file.getName() ) )
89              {
90                  // TODO: provide better warning
91                  result = false;
92              }
93              trimmedChecksum = m.group( 2 );
94          }
95          else
96          {
97              // GNU tools
98              m = Pattern.compile( "([a-zA-Z0-9]+)\\s\\*?(.+)" ).matcher( trimmedChecksum );
99              if ( m.matches() )
100             {
101                 String filename = m.group( 2 );
102                 if ( !filename.equals( file.getName() ) )
103                 {
104                     // TODO: provide better warning
105                     result = false;
106                 }
107                 trimmedChecksum = m.group( 1 );
108             }
109         }
110 
111         if ( result )
112         {
113             //Create checksum for jar file
114             String sum = createChecksum( file, algorithm );
115             result = trimmedChecksum.toUpperCase().equals( sum.toUpperCase() );
116         }
117         return result;
118     }
119 
120     /**
121      * Convert an incoming array of bytes into a string that represents each of
122      * the bytes as two hex characters.
123      *
124      * @param data
125      */
126     private static String byteArrayToHexStr( byte[] data )
127     {
128         String output = "";
129 
130         for ( int cnt = 0; cnt < data.length; cnt++ )
131         {
132             //Deposit a byte into the 8 lsb of an int.
133             int tempInt = data[cnt] & BYTE_MASK;
134 
135             //Get hex representation of the int as a string.
136             String tempStr = Integer.toHexString( tempInt );
137 
138             //Append a leading 0 if necessary so that each hex string will contain 2 characters.
139             if ( tempStr.length() == 1 )
140             {
141                 tempStr = "0" + tempStr;
142             }
143 
144             //Concatenate the two characters to the output string.
145             output = output + tempStr;
146         }
147 
148         return output.toUpperCase();
149     }
150 }