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, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.commons.crypto;
019
020import java.io.IOException;
021import java.io.InputStream;
022import java.net.URL;
023import java.util.Properties;
024
025import org.apache.commons.crypto.cipher.CryptoCipher;
026import org.apache.commons.crypto.cipher.CryptoCipherFactory;
027import org.apache.commons.crypto.random.CryptoRandom;
028import org.apache.commons.crypto.random.CryptoRandomFactory;
029import org.apache.commons.crypto.utils.AES;
030
031/**
032 * Provides diagnostic information about Commons Crypto and keys for native
033 * class loading.
034 */
035public final class Crypto {
036
037    private static class ComponentPropertiesHolder {
038
039        static final Properties PROPERTIES = getComponentProperties();
040
041        /**
042         * Get component properties from component.properties.
043         *
044         * @return Properties contains project version.
045         */
046        private static Properties getComponentProperties() {
047            final URL url = Crypto.class.getResource("/org/apache/commons/crypto/component.properties");
048            final Properties versionData = new Properties();
049            if (url != null) {
050                try (InputStream inputStream = url.openStream()) {
051                    versionData.load(inputStream);
052                } catch (final IOException e) { // NOPMD
053                }
054            }
055            return versionData;
056        }
057    }
058
059    /**
060     * The prefix of all crypto configuration keys.
061     */
062    public static final String CONF_PREFIX = "commons.crypto.";
063
064    /**
065     * The configuration key of the file name for loading crypto library.
066     */
067
068    public static final String LIB_NAME_KEY = Crypto.CONF_PREFIX + "lib.name";
069
070    // native lib related configuration keys
071    /**
072     * The configuration key of the path for loading crypto library.
073     */
074    public static final String LIB_PATH_KEY = Crypto.CONF_PREFIX + "lib.path";
075
076    /**
077     * The configuration key of temp directory for extracting crypto library.
078     * Defaults to "java.io.tempdir" if not found.
079     */
080    public static final String LIB_TEMPDIR_KEY = Crypto.CONF_PREFIX + "lib.tempdir";
081
082    private static boolean quiet = false;
083
084    /**
085     * Gets the component version of Apache Commons Crypto.
086     * <p>
087     * This implementation relies on the VERSION properties file which must be set
088     * up with the correct contents by the build process. This is done automatically
089     * by Maven.
090     * </p>
091     *
092     * @return the version; may be null if not found
093     */
094    public static String getComponentName() {
095        // Note: the component properties file allows the method to work without needing
096        // the jar
097        return ComponentPropertiesHolder.PROPERTIES.getProperty("NAME");
098    }
099
100    /**
101     * Gets the component version of Apache Commons Crypto.
102     * <p>
103     * This implementation relies on the VERSION properties file which must be set
104     * up with the correct contents by the build process. This is done automatically
105     * by Maven.
106     * </p>
107     *
108     * @return the version; may be null if not found
109     */
110    public static String getComponentVersion() {
111        // Note: the component properties file allows the method to work without needing
112        // the jar
113        return ComponentPropertiesHolder.PROPERTIES.getProperty("VERSION");
114    }
115
116    /**
117     * The loading error throwable, if loading failed.
118     *
119     * @return null, unless loading failed.
120     */
121    public static Throwable getLoadingError() {
122        return NativeCodeLoader.getLoadingError();
123    }
124
125    /**
126     * Logs info-level messages.
127     *
128     * @param format See {@link String#format(String, Object...)}.
129     * @param args   See {@link String#format(String, Object...)}.
130     */
131    private static void info(final String format, final Object... args) {
132        if (!quiet) { // suppress output for testing
133          System.out.println(String.format(format, args));
134        }
135    }
136
137    /**
138     * Checks whether the native code has been successfully loaded for the platform.
139     *
140     * @return true if the native code has been loaded successfully.
141     */
142    public static boolean isNativeCodeLoaded() {
143        return NativeCodeLoader.isNativeCodeLoaded();
144    }
145
146    /**
147     * The Main of Crypto.
148     *
149     * @param args Not used.
150     * @throws Exception if getCryptoRandom or getCryptoCipher get error.
151     */
152    public static void main(final String[] args) throws Exception {
153        quiet = args.length == 1 && args[0].equals("-q");
154        info("%s %s", getComponentName(), getComponentVersion());
155        if (isNativeCodeLoaded()) {
156            info("Native code loaded OK: %s", OpenSslInfoNative.NativeVersion());
157            info("Native name: %s", OpenSslInfoNative.NativeName());
158            info("Native built: %s", OpenSslInfoNative.NativeTimeStamp());
159            info("OpenSSL library loaded OK, version: 0x%s", Long.toHexString(OpenSslInfoNative.OpenSSL()));
160            info("OpenSSL library info: %s", OpenSslInfoNative.OpenSSLVersion(0));
161            info("DLL name: %s", OpenSslInfoNative.DLLName());
162            info("DLL path: %s", OpenSslInfoNative.DLLPath());
163            { // CryptoRandom
164                final Properties props = new Properties();
165                props.setProperty(CryptoRandomFactory.CLASSES_KEY, CryptoRandomFactory.RandomProvider.OPENSSL.getClassName());
166                try (CryptoRandom cryptoRandom = CryptoRandomFactory.getCryptoRandom(props)) {
167                    info("Random instance created OK: %s", cryptoRandom);
168                }
169            }
170            { // CryptoCipher
171                final Properties props = new Properties();
172                props.setProperty(CryptoCipherFactory.CLASSES_KEY, CryptoCipherFactory.CipherProvider.OPENSSL.getClassName());
173                try (CryptoCipher cryptoCipher = CryptoCipherFactory.getCryptoCipher(AES.CTR_NO_PADDING, props)) {
174                    info("Cipher %s instance created OK: %s", AES.CTR_NO_PADDING, cryptoCipher);
175                }
176            }
177            info("Additional OpenSSL_version(n) details:");
178            for (int j = 1; j < 6; j++) {
179                info("%s: %s", j, OpenSslInfoNative.OpenSSLVersion(j));
180            }
181        } else {
182            info("Native load failed: %s", getLoadingError());
183        }
184    }
185
186}