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.eclipse.aether.util;
20  
21  import java.nio.charset.StandardCharsets;
22  import java.security.MessageDigest;
23  import java.security.NoSuchAlgorithmException;
24  
25  /**
26   * A simple digester utility for Strings. Uses {@link MessageDigest} for requested algorithm. Supports one-pass or
27   * several rounds of updates, and as result emits hex encoded String.
28   *
29   * @since 1.9.0
30   */
31  public final class StringDigestUtil {
32      private final MessageDigest digest;
33  
34      /**
35       * Constructs instance with given algorithm.
36       *
37       * @see #sha1()
38       * @see #sha1(String)
39       */
40      public StringDigestUtil(final String alg) {
41          try {
42              this.digest = MessageDigest.getInstance(alg);
43          } catch (NoSuchAlgorithmException e) {
44              throw new IllegalStateException("Not supported digest algorithm: " + alg);
45          }
46      }
47  
48      /**
49       * Updates instance with passed in string.
50       */
51      public StringDigestUtil update(String data) {
52          if (data != null && !data.isEmpty()) {
53              digest.update(data.getBytes(StandardCharsets.UTF_8));
54          }
55          return this;
56      }
57  
58      /**
59       * Returns the digest of all strings passed via {@link #update(String)} as hex string. There is no state preserved
60       * and due implementation of {@link MessageDigest#digest()}, same applies here: this instance "resets" itself.
61       * Hence, the digest hex encoded string is returned only once.
62       *
63       * @see MessageDigest#digest()
64       */
65      public String digest() {
66          return toHexString(digest.digest());
67      }
68  
69      /**
70       * Helper method to create {@link StringDigestUtil} using SHA-1 digest algorithm.
71       */
72      public static StringDigestUtil sha1() {
73          return new StringDigestUtil("SHA-1");
74      }
75  
76      /**
77       * Helper method to calculate SHA-1 digest and hex encode it.
78       */
79      public static String sha1(final String string) {
80          return sha1().update(string).digest();
81      }
82  
83      /**
84       * Creates a hexadecimal representation of the specified bytes. Each byte is converted into a two-digit hex number
85       * and appended to the result with no separator between consecutive bytes.
86       *
87       * @param bytes The bytes to represent in hex notation, may be {@code null}.
88       * @return The hexadecimal representation of the input or {@code null} if the input was {@code null}.
89       * @since 2.0.0
90       */
91      public static String toHexString(byte[] bytes) {
92          if (bytes == null) {
93              return null;
94          }
95  
96          StringBuilder buffer = new StringBuilder(bytes.length * 2);
97  
98          for (byte aByte : bytes) {
99              int b = aByte & 0xFF;
100             if (b < 0x10) {
101                 buffer.append('0');
102             }
103             buffer.append(Integer.toHexString(b));
104         }
105 
106         return buffer.toString();
107     }
108 
109     /**
110      * Creates a byte array out of hexadecimal representation of the specified bytes. If input string is {@code null},
111      * {@code null} is returned. Input value must have even length (due hex encoding = 2 chars one byte).
112      *
113      * @param hexString The hexString to convert to byte array, may be {@code null}.
114      * @return The byte array of the input or {@code null} if the input was {@code null}.
115      * @since 2.0.0
116      */
117     public static byte[] fromHexString(String hexString) {
118         if (hexString == null) {
119             return null;
120         }
121         if (hexString.isEmpty()) {
122             return new byte[] {};
123         }
124         int len = hexString.length();
125         if (len % 2 != 0) {
126             throw new IllegalArgumentException("hexString length not even");
127         }
128         byte[] data = new byte[len / 2];
129         for (int i = 0; i < len; i += 2) {
130             data[i / 2] = (byte)
131                     ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
132         }
133         return data;
134     }
135 }