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

io.mangoo.utils.CodecUtils Maven / Gradle / Ivy

The newest version!
package io.mangoo.utils;

import com.fasterxml.uuid.Generators;
import io.mangoo.constants.Key;
import io.mangoo.constants.NotNull;
import io.mangoo.core.Application;
import io.mangoo.core.Config;
import org.apache.fury.Fury;
import org.apache.fury.ThreadSafeFury;
import org.apache.fury.config.Language;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;
import org.bouncycastle.util.Arrays;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HexFormat;
import java.util.Objects;

public final class CodecUtils {
    private static final Logger LOG = LogManager.getLogger(CodecUtils.class);
    private static final Base64.Encoder BASE64ENCODER = Base64.getEncoder();
    private static final Base64.Decoder BASE64DECODER = Base64.getDecoder();
    private static final ThreadSafeFury FURY = Fury.builder()
            .withLanguage(Language.JAVA)
            .requireClassRegistration(false)
            .buildThreadSafeFury();

    private CodecUtils() {
    }
    
    /**
     * Hashes a given clear text  with a given salt using Argon2Id hashing
     * 
     * @param cleartext The clear text
     * @param salt The salt
     * 
     * @return A Base64 encoded String
     */
    public static String hashArgon2(String cleartext, String salt) {
        Objects.requireNonNull(cleartext, NotNull.CLEARTEXT);
        Objects.requireNonNull(salt, NotNull.SALT);

        var argon2 = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withVersion(Argon2Parameters.ARGON2_VERSION_13)
                .withParallelism(2)
                .withMemoryAsKB(100000)
                .withSalt(salt.getBytes(StandardCharsets.UTF_8))
                .withIterations(16)
                .build();

        var argon2Generator = new Argon2BytesGenerator();
        argon2Generator.init(argon2);

        var hash = new byte[32];
        argon2Generator.generateBytes(cleartext.getBytes(StandardCharsets.UTF_8), hash);

        return BASE64ENCODER.encodeToString(hash);
    }

    /**
     * Hashes a given clear text with the application secret as salt using Argon2Id hashing
     *
     * @param cleartext The clear text
     *
     * @return A Base64 encoded String
     */
    public static String hashArgon2(String cleartext) {
        Objects.requireNonNull(cleartext, NotNull.CLEARTEXT);

        var salt = Application.getInstance(Config.class).getString(Key.APPLICATION_SECRET);
        return hashArgon2(cleartext, salt);
    }
    
    /**
     * Matches a given clear text with salt using Argon2Id against an already Argon2Id hashed value
     * 
     * @param cleartext The clear text
     * @param salt The salt
     * @param hash The hashed value for comparison (must be Base64 encoded)
     * 
     * @return True if hashes match, false otherwise
     */
    public static boolean matchArgon2(String cleartext, String salt, String hash) {
        Objects.requireNonNull(cleartext, NotNull.CLEARTEXT);
        Objects.requireNonNull(salt, NotNull.SALT);
        Objects.requireNonNull(hash, NotNull.HASH);

        return Arrays.areEqual(hashArgon2(cleartext, salt).getBytes(StandardCharsets.UTF_8), hash.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Matches a given clear text using the application secret as salt using Argon2Id against an already Argon2Id hashed value
     *
     * @param cleartext The clear text
     * @param hash The hashed value for comparison (must be Base64 encoded)
     *
     * @return True if hashes match, false otherwise
     */
    public static boolean matchArgon2(String cleartext, String hash) {
        Objects.requireNonNull(cleartext, NotNull.CLEARTEXT);
        Objects.requireNonNull(hash, NotNull.HASH);

        var salt = Application.getInstance(Config.class).getString(Key.APPLICATION_SECRET);

        return Arrays.areEqual(hashArgon2(cleartext, salt).getBytes(StandardCharsets.UTF_8), hash.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * Hashes a given clear text data with SHA3-512
     * For simple hashing tasks
     * 
     * @param data The clear text data
     * @return SHA512 hashed value or null if hashing failed
     */
    public static String hexSHA512(String data) {
        Objects.requireNonNull(data, NotNull.DATA);

        try {
            var digest = MessageDigest.getInstance("SHA3-512");
            byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));

            return HexFormat.of().formatHex(hashBytes);
        } catch (NoSuchAlgorithmException e) {
            LOG.error("Failed to create hash of data", e);
        }

        return null;
    }
    
    /**
     * Serializes an object into a Base64 encoded data string
     *
     * @param object The object to serialize
     * @return The base64 encoded data string
     */
    public static String serializeToBase64(Serializable object)  {
        Objects.requireNonNull(object, NotNull.OBJECT);
        
        byte[] serialize = FURY.serialize(object);
        return BASE64ENCODER.encodeToString(serialize);
    }
    
    /**
     * Deserializes a given Base64 encoded data string into an object
     * 
     * @param data The base64 encoded data string
     * @param  Just for JavaDoc can be ignored
     * @return The required object
     */
    @SuppressWarnings("unchecked")
    public static  T deserializeFromBase64(String data) {
        Objects.requireNonNull(data, NotNull.DATA);
        
        byte[] bytes = BASE64DECODER.decode(data);
        return (T) FURY.deserialize(bytes);
    }
    
    /**
     * Encodes a given string to a Base64 byte array
     * 
     * @param data The data to convert
     * @return The converted byte array
     */
    public static byte[] encodeToBase64(String data) {
        Objects.requireNonNull(data, NotNull.DATA);
        return BASE64ENCODER.encode(data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Encodes a given string to a Base64 byte array
     *
     * @param data The data to convert
     * @return The converted byte array
     */
    public static byte[] encodeToBase64(byte[] data) {
        Objects.requireNonNull(data, NotNull.DATA);
        return BASE64ENCODER.encode(data);
    }
    
    /**
     * Decodes a given Base64 encoded string to a byte array
     * 
     * @param data The data to convert
     * @return The converted byte array
     */
    public static byte[] decodeFromBase64(String data) {
        Objects.requireNonNull(data, NotNull.DATA);
        return BASE64DECODER.decode(data);
    }

    /**
     * Creates a UUIDv6 random String
     *
     * @return UUIDv6 String
     */
    public static String uuid() {
        return Generators.timeBasedReorderedGenerator().generate().toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy