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

com.weavechain.core.encrypt.Hash Maven / Gradle / Ivy

There is a newer version: 1.3
Show newest version
package com.weavechain.core.encrypt;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.pqc.crypto.xmss.XMSSMT;
import org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Hash {

    static final Logger logger = LoggerFactory.getLogger(Hash.class);

    public static final String HmacSHA256 = "HmacSHA256";

    public static final String HmacSHA512 = "HmacSHA512";

    public static final String SHA256 = "SHA-256";

    public static final String SHA512 = "SHA-512";

    public static final String Keccak256 = "Keccak-256";

    public static final String Keccak512 = "Keccak-512";

    public static final String SaltedKeccak256 = "SaltedKeccak256";

    public static final String SaltedKeccak512 = "SaltedKeccak512";

    public static final String SaltedSHA256 = "SaltedSHA256";

    public static final String SaltedSHA512 = "SaltedSHA512";

    public static final String Blake2 = "Blake2";

    public static final String SaltedSHA512SPHINCS256 = "SaltedSHA512SPHINCS256";

    public static final String SaltedXMSS256 = "SaltedXMSS256";

    public static final String SaltedXMSS512 = "SaltedXMSS512";

    private static final int XMSSMT_HEIGHT = 10;

    private static final int XMSSMT_LAYERS = 5;

    private static final SecureRandom RND = new SecureRandom();

    private static String hash;

    private static KeyPair keyPair;

    public static void initHashing(String hash, PrivateKey privateKey) {
        Hash.hash = hash;
        keyPair = KeysProvider.deriveSphincsKeyPair(privateKey);
    }

    public static String signRequest(String secret, String data) {
        byte[] result = signRequestRaw(secret, data);
        //TODO: use byte[] signatures in blockchains, fast String solution for PoC
        return result != null ? Base64.encodeBase64String(result) : null;
    }


    public static byte[] signRequestRaw(String secret, String data) {
        //TODO: optimize, keep secret decoded
        return signBytes(secret.getBytes(StandardCharsets.UTF_8), data.getBytes(StandardCharsets.UTF_8), null);
    }

    public static String signRequestB64(String secret, String data) {
        byte[] result = signBytes(Base64.decodeBase64(secret.getBytes()), data.getBytes(StandardCharsets.UTF_8), null);
        return result != null ? Base64.encodeBase64String(result) : null;
    }

    public static String signRequestBytes(String secret, byte[] data) {
        byte[] result = signBytes(Base64.decodeBase64(secret.getBytes()), data, null);
        return result != null ? Base64.encodeBase64String(result) : null;
    }

    public static byte[] signString(byte[] secret, String data, String digest) {
        return signBytes(secret, data.getBytes(StandardCharsets.UTF_8), digest);
    }

    public static int getHashLength(String digest) {
        if (digest == null
                || HmacSHA256.equals(digest)
                || SaltedSHA256.equals(digest)
                || SaltedKeccak256.equals(digest)
                || SHA256.equals(digest)
                || Keccak256.equals(digest)
        ) {
            return 32;
        } else if (HmacSHA512.equals(digest)
                || SaltedSHA512.equals(digest)
                || SaltedKeccak512.equals(digest)
                || SHA512.equals(digest)
                || Keccak512.equals(digest)
                || Blake2.equals(digest)
        ) {
            return 64;
        } else if (SaltedXMSS256.equals(digest)) {
            return 11074;
        } else if (SaltedXMSS512.equals(digest)) {
            return 42626;
        } else if (SaltedSHA512SPHINCS256.equals(digest)) {
            return 41000;
        } else {
            return 32;
        }
    }

    public static byte[] signBytes(byte[] secret, byte[] data, String digest) {
        try {
            String hash = digest != null ? digest : Hash.hash;

            byte[] result = null;
            if (hash == null || HmacSHA256.equals(hash) || SHA256.equals(hash)) {
                if (secret != null) {
                    Mac mac = Mac.getInstance("HmacSHA256");
                    mac.init(new SecretKeySpec(secret, "HmacSHA256"));
                    result = mac.doFinal(data);
                } else {
                    MessageDigest md = MessageDigest.getInstance("SHA-256");
                    result = md.digest(data);
                }
            } else if (HmacSHA512.equals(hash) || SHA512.equals(hash)) {
                if (secret != null) {
                    Mac mac = Mac.getInstance("HmacSHA512");
                    mac.init(new SecretKeySpec(secret, "HmacSHA512"));
                    result = mac.doFinal(data);
                } else {
                    MessageDigest md = MessageDigest.getInstance("SHA-512");
                    result = md.digest(data);
                }
            } else if (SaltedSHA256.equals(hash)) {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                result = md.digest(getSaltedBytes(secret, data));
            } else if (SaltedSHA512.equals(hash)) {
                MessageDigest md = MessageDigest.getInstance("SHA-512");
                result = md.digest(getSaltedBytes(secret, data));
            } else if (SaltedKeccak256.equals(hash) || Keccak256.equals(hash)) {
                MessageDigest md = MessageDigest.getInstance("Keccak-256");
                result = md.digest(getSaltedBytes(secret, data));
            } else if (SaltedKeccak512.equals(hash) || Keccak512.equals(hash)) {
                MessageDigest md = MessageDigest.getInstance("Keccak-512");
                result = md.digest(getSaltedBytes(secret, data));
            } else if (Blake2.equals(hash)) {
                Blake2bDigest b2 = new Blake2bDigest(null, 64, secret, null);
                b2.update(data, 0, data.length);
                result = new byte[64];
                b2.doFinal(result, 0);
            } else if (SaltedXMSS256.equals(hash)) {
                XMSSMTParameters params = new XMSSMTParameters(XMSSMT_HEIGHT, XMSSMT_LAYERS, new SHA256Digest());
                XMSSMT mt = new XMSSMT(params, RND);
                mt.generateKeys();
                result = mt.sign(getSaltedBytes(secret, data));
            } else if (SaltedXMSS512.equals(hash)) {
                XMSSMTParameters params = new XMSSMTParameters(XMSSMT_HEIGHT, XMSSMT_LAYERS, new SHA512Digest());
                XMSSMT mt = new XMSSMT(params, RND);
                mt.generateKeys();
                result = mt.sign(getSaltedBytes(secret, data));
            } else if (SaltedSHA512SPHINCS256.equals(hash)) {
                Signature sig = Signature.getInstance("SHA3-512withSPHINCS256", KeysProvider.POST_QUANTUM_PROVIDER);
                sig.initSign(keyPair.getPrivate());

                byte[] salted = getSaltedBytes(secret, data);
                sig.update(salted, 0, salted.length);
                result = sig.sign();
            }
            return result;
        } catch (Exception e) {
            logger.error("Failed signing request", e);
            return null;
        }
    }

    private static byte[] getSaltedBytes(byte[] secret, byte[] data) {
        if (secret != null) {
            byte[] salted = new byte[secret.length + data.length];
            System.arraycopy(secret, 0, salted, 0, secret.length);
            System.arraycopy(data, 0, salted, secret.length, data.length);
            return salted;
        } else {
            return data;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy