All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.inugami.commons.security.EncryptionUtils Maven / Gradle / Ivy

There is a newer version: 3.3.5
Show newest version
/* --------------------------------------------------------------------
 *  Inugami
 * --------------------------------------------------------------------
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see .
 */
package io.inugami.commons.security;

import io.inugami.api.constants.JvmKeyValues;
import io.inugami.api.exceptions.Asserts;
import io.inugami.api.exceptions.FatalException;
import io.inugami.api.loggers.Loggers;
import io.inugami.commons.files.FilesUtils;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;

/**
 * EncryptionUtils
 *
 * @author patrick_guillerm
 * @since 27 oct. 2016
 */
@SuppressWarnings({"java:S2245"})
public class EncryptionUtils {

    // =========================================================================
    // ATTRIBUTES
    // =========================================================================
    private final static Properties DEFAULT_PROPERTIES = loadDefaultProperties();

    //@formatter:off
    /**
     * @see io.inugami.api.constants.JvmKeyValues.SECURITY_CRYPTOGRAPHIC_KEYS
     */
    private final static String[] CRYPTO_DEFINITION = initCryptoDefinition();

    /**
     * The Constant CHAR_DOT.
     */
    protected static final String CHAR_UNDERSCORE = assertLenght(CRYPTO_DEFINITION[0], 1, "invalide char underscore definition");

    /**
     * The Constant CHAR_AND.
     */
    protected static final String CHAR_AND = assertLenght(CRYPTO_DEFINITION[1], 1, "invalide char and definition");

    /**
     * The Constant CHAR_DOUBLE_DOT.
     */
    protected static final String CHAR_MINUS = assertLenght(CRYPTO_DEFINITION[2], 1, "invalide char minus definition");

    /**
     * The Constant CHAR_PLUS.
     */
    protected static final String CHAR_PLUS = assertLenght(CRYPTO_DEFINITION[3], 1, "invalide char plus definition");

    /**
     * The Constant CHAR_AT.
     */
    protected static final String CHAR_AT = assertLenght(CRYPTO_DEFINITION[4], 1, "invalide char at definition");

    /**
     * The Constant CHAR_SLASH.
     */
    protected static final String CHAR_SLASH = assertLenght(CRYPTO_DEFINITION[5], 1, "invalide char slash definition");
    //@formatter:on

    private static final Random RANDOM = new Random((new Date()).getTime());

    /**
     * @see io.inugami.api.constants.JvmKeyValues.SECURITY_TOKEN_MAX_SIZE
     */
    private static final int TOKEN_MAX_SIZE = Integer.parseInt(load(JvmKeyValues.SECURITY_TOKEN_MAX_SIZE));

    /**
     * @see io.inugami.api.constants.JvmKeyValues.SERCURITY_CIPHER
     */
    private static final String CIPHER_ALGORITHM = load(JvmKeyValues.SERCURITY_CIPHER_ALGO);

    private static final String KEY_ALGORITHM = load(JvmKeyValues.SERCURITY_CIPHER_ALGO_KEY);

    private static final Charset UTF_8 = Charset.forName(load(JvmKeyValues.SERCURITY_ENCODING));

    /**
     * @see io.inugami.api.constants.JvmKeyValues.SECURITY_AES_SECRET_KET
     */
    private static final byte[] SECRET_KEY = loadSecretKey();

    // =========================================================================
    // INIT
    // =========================================================================
    private static byte[] loadSecretKey() {
        final String config = JvmKeyValues.SECURITY_AES_SECRET_KEY.or("16BYTESSECRETKEY");
        return config.getBytes(UTF_8);
    }

    private static String assertLenght(final String value, final int size, final String message) {
        if ((value == null) || (value.length() != size)) {
            throw new FatalException(message);
        }
        return value;
    }

    private static String load(final JvmKeyValues key) {
        return key.or(DEFAULT_PROPERTIES.get(key.getKey()));
    }

    private static Properties loadDefaultProperties() {
        final Properties  result = new Properties();
        final InputStream stream = EncryptionUtils.class.getClassLoader().getResourceAsStream("META-INF/inugami_commons.properties");
        try {
            result.load(stream);
        } catch (final IOException e) {
            throw new FatalException(e.getMessage(), e);
        } finally {
            FilesUtils.close(stream);
        }
        return result;
    }

    private static String[] initCryptoDefinition() {
        final String       config = load(JvmKeyValues.SECURITY_CRYPTOGRAPHIC_KEYS);
        final List result = new ArrayList<>();
        for (final char item : config.toCharArray()) {
            result.add(new StringBuilder().append(item).toString());
        }
        Asserts.assertTrue(result.size() == 6);
        return result.toArray(new String[]{});
    }

    // =========================================================================
    // Token
    // =========================================================================
    public synchronized String makeUniqueToken() {
        String result = null;

        final long   time     = System.currentTimeMillis();
        final long   timeNano = System.nanoTime();
        final String timeStr  = String.valueOf(time) + String.valueOf(timeNano);

        final String timeSha1;
        timeSha1 = encodeSha1(timeStr);

        String    randomToken = "";
        final int nbKeys      = TOKEN_MAX_SIZE - timeSha1.length();
        if (nbKeys > 0) {
            randomToken = UUID.randomUUID().toString();
        }

        result = encodeSha1(timeSha1 + randomToken);

        return result;
    }

    // =========================================================================
    // SHA 1
    // =========================================================================

    private static String encodeToSha1(final String value) {
        String result = null;
        try {
            final MessageDigest md = MessageDigest.getInstance("SHA-512");
            md.update(loadSecretKey());
            final byte[] bytes = md.digest(value.getBytes(StandardCharsets.UTF_8));
            result = Hex.encodeHexString(bytes);
        } catch (final NoSuchAlgorithmException e) {
            Loggers.DEBUG.error(e.getMessage(), e);
        }
        return result;
    }


    public String encodeSha1(final String value) {
        return encodeToSha1(value);
    }

    // =========================================================================
    // AES
    // =========================================================================
    public String encodeAES(final String value) {
        byte[] data = null;
        try {
            final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(SECRET_KEY, KEY_ALGORITHM));
            data = cipher.doFinal(value.getBytes(Charsets.UTF_8));

        } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
                       IllegalBlockSizeException
                       | BadPaddingException e) {
            throw new SecurityException(e.getMessage(), e);
        }

        return encodeBase64(data);
    }


    public String decodeAES(final String value) {

        try {
            final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(SECRET_KEY, KEY_ALGORITHM));
            return new String(cipher.doFinal(Base64.decodeBase64(value)), Charsets.UTF_8);
        } catch (final NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException |
                       IllegalBlockSizeException
                       | BadPaddingException e) {
            throw new SecurityException(e.getMessage(), e);
        }

    }

    // =========================================================================
    // AES
    // =========================================================================

    public String encodeHexa(final String value) {
        return Hex.encodeHexString(value.getBytes());
    }


    public String decodeHexa(final String value) throws DecoderException {
        return new String(Hex.decodeHex(value.toCharArray()));
    }

    // =========================================================================
    // BASE 64
    // =========================================================================

    public String encodeBase64(final String value) {
        return encodeBase64(value == null ? null : value.getBytes(UTF_8));
    }

    public String encodeBase64(final byte[] value) {
        if (value == null) {
            return null;
        }
        return Base64.encodeBase64URLSafeString(value);
    }


    public String decodeBase64(final String value) {
        return new String(decodeBase64Bytes(value));

    }

    public byte[] decodeBase64Bytes(final String value) {
        if (value == null) {
            return null;
        }
        return Base64.decodeBase64(value.getBytes(UTF_8));
    }

    // =========================================================================
    // Map <-> String
    // =========================================================================

    public String encodeMap(final Map value) {
        final StringBuilder result = new StringBuilder();
        if ((value == null) || value.isEmpty()) {
            return result.toString();
        }

        final Iterator> iterator = value.entrySet().iterator();
        while (iterator.hasNext()) {
            final Entry entry = iterator.next();
            result.append(entry.getKey());
            result.append(CHAR_MINUS);
            result.append(entry.getValue());

            if (iterator.hasNext()) {
                result.append(CHAR_AT);
            }
        }
        return result.toString();
    }


    public Map decodeMap(final String value) {
        final Map result = new HashMap<>();

        final String[] values = value.split(CHAR_AT);
        for (final String item : values) {
            final String[] composite = item.split(CHAR_MINUS);
            if (composite.length == 2) {
                result.put(composite[0], composite[1]);
            }
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy