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.james.user.lib.util;
021    
022    import javax.mail.MessagingException;
023    import javax.mail.internet.MimeUtility;
024    
025    import java.io.ByteArrayOutputStream;
026    import java.io.FileInputStream;
027    import java.io.FileOutputStream;
028    import java.io.IOException;
029    import java.io.OutputStream;
030    import java.security.MessageDigest;
031    import java.security.NoSuchAlgorithmException;
032    import java.util.Locale;
033    
034    /**
035     * Computes and verifies digests of files and strings
036     */
037    public class DigestUtil {
038    
039        /**
040         * Command line interface. Use -help for arguments.
041         * 
042         * @param args
043         *            the arguments passed in on the command line
044         */
045        public static void main(String[] args) {
046    
047            String alg = "SHA";
048            boolean file = false;
049    
050            if (args.length == 0 || args.length > 4) {
051                printUsage();
052                return;
053            }
054    
055            for (int i = 0; i < args.length; i++) {
056                String currArg = args[i].toLowerCase(Locale.US);
057                if (currArg.equals("-help") || currArg.equals("-usage")) {
058                    printUsage();
059                    return;
060                }
061                if (currArg.equals("-alg")) {
062                    alg = args[i + 1];
063                }
064                if (currArg.equals("-file")) {
065                    file = true;
066                }
067            }
068    
069            if (file) {
070                digestFile(args[args.length - 1], alg);
071                return;
072            } else {
073                try {
074                    String hash = digestString(args[args.length - 1], alg);
075                    System.out.println("Hash is: " + hash);
076                    return;
077                } catch (NoSuchAlgorithmException nsae) {
078                    System.out.println("No such algorithm available");
079                }
080            }
081        }
082    
083        /**
084         * Print the command line usage string.
085         */
086        public static void printUsage() {
087            System.out.println("Usage: " + "java org.apache.james.security.DigestUtil" + " [-alg algorithm]" + " [-file] filename|string");
088        }
089    
090        /**
091         * Calculate digest of given file with given algorithm. Writes digest to
092         * file named filename.algorithm .
093         * 
094         * @param filename
095         *            the String name of the file to be hashed
096         * @param algorithm
097         *            the algorithm to be used to compute the digest
098         */
099        public static void digestFile(String filename, String algorithm) {
100            byte[] b = new byte[65536];
101            int count = 0;
102            int read = 0;
103            FileInputStream fis = null;
104            FileOutputStream fos = null;
105            try {
106                MessageDigest md = MessageDigest.getInstance(algorithm);
107                fis = new FileInputStream(filename);
108                while (fis.available() > 0) {
109                    read = fis.read(b);
110                    md.update(b, 0, read);
111                    count += read;
112                }
113                byte[] digest = md.digest();
114                StringBuffer fileNameBuffer = new StringBuffer(128).append(filename).append(".").append(algorithm);
115                fos = new FileOutputStream(fileNameBuffer.toString());
116                OutputStream encodedStream = MimeUtility.encode(fos, "base64");
117                encodedStream.write(digest);
118                fos.flush();
119            } catch (Exception e) {
120                System.out.println("Error computing Digest: " + e);
121            } finally {
122                try {
123                    fis.close();
124                    fos.close();
125                } catch (Exception ignored) {
126                }
127            }
128        }
129    
130        /**
131         * Calculate digest of given String using given algorithm. Encode digest in
132         * MIME-like base64.
133         * 
134         * @param pass
135         *            the String to be hashed
136         * @param algorithm
137         *            the algorithm to be used
138         * @return String Base-64 encoding of digest
139         * 
140         * @throws NoSuchAlgorithmException
141         *             if the algorithm passed in cannot be found
142         */
143        public static String digestString(String pass, String algorithm) throws NoSuchAlgorithmException {
144    
145            MessageDigest md;
146            ByteArrayOutputStream bos;
147    
148            try {
149                md = MessageDigest.getInstance(algorithm);
150                byte[] digest = md.digest(pass.getBytes("iso-8859-1"));
151                bos = new ByteArrayOutputStream();
152                OutputStream encodedStream = MimeUtility.encode(bos, "base64");
153                encodedStream.write(digest);
154                return bos.toString("iso-8859-1");
155            } catch (IOException ioe) {
156                throw new RuntimeException("Fatal error: " + ioe);
157            } catch (MessagingException me) {
158                throw new RuntimeException("Fatal error: " + me);
159            }
160        }
161    
162        /**
163         * Private constructor to prevent instantiation of the class
164         */
165        private DigestUtil() {
166        }
167    }