dev.fitko.fitconnect.core.crypto.HashService Maven / Gradle / Ivy
package dev.fitko.fitconnect.core.crypto;
import dev.fitko.fitconnect.api.exceptions.internal.EncryptionException;
import dev.fitko.fitconnect.api.services.crypto.MessageDigestService;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import static dev.fitko.fitconnect.core.crypto.constants.CryptoConstants.DEFAULT_HASH_ALGORITHM;
import static dev.fitko.fitconnect.core.crypto.constants.CryptoConstants.DEFAULT_HMAC_ALGORITHM;
public class HashService implements MessageDigestService {
@Override
public byte[] createHash(final byte[] data) {
try {
final var messageDigest = MessageDigest.getInstance(DEFAULT_HASH_ALGORITHM);
return messageDigest.digest(data);
} catch (final NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
@Override
public byte[] createHash(final InputStream inputStream) {
try {
final var messageDigest = MessageDigest.getInstance(DEFAULT_HASH_ALGORITHM);
final byte[] buffer = new byte[8192];
for (int read; (read = inputStream.read(buffer)) != -1; ) {
messageDigest.update(buffer, 0, read);
}
return messageDigest.digest();
} catch (final NoSuchAlgorithmException | IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean verify(final byte[] originalHash, final byte[] data) {
final byte[] newHash = createHash(data);
return compareHashes(originalHash, newHash);
}
@Override
public boolean verify(final byte[] originalHash, final InputStream data) {
final byte[] newHash = createHash(data);
return compareHashes(originalHash, newHash);
}
@Override
public String toHexString(final byte[] hash) {
final StringBuilder hexStringBuffer = new StringBuilder();
for (final byte b : hash) {
hexStringBuffer.append(byteToHex(b));
}
return hexStringBuffer.toString();
}
@Override
public byte[] fromHexString(final String hexString) {
if (hexString.length() % 2 == 1) {
throw new IllegalArgumentException("Invalid hexadecimal String.");
}
final byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
bytes[i / 2] = hexToByte(hexString.substring(i, i + 2));
}
return bytes;
}
@Override
public String calculateHMAC(final String data, final String key) {
try {
final String hmacAlgorithm = DEFAULT_HMAC_ALGORITHM;
final SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), hmacAlgorithm);
final Mac mac = Mac.getInstance(hmacAlgorithm);
mac.init(secretKeySpec);
return toHexString(mac.doFinal(data.getBytes()));
} catch (final NoSuchAlgorithmException | InvalidKeyException e) {
throw new EncryptionException("Calculation of HMAC failed.", e);
}
}
private byte hexToByte(final String hexString) {
final int firstDigit = toDigit(hexString.charAt(0));
final int secondDigit = toDigit(hexString.charAt(1));
return (byte) ((firstDigit << 4) + secondDigit);
}
private int toDigit(final char hexChar) {
final int digit = Character.digit(hexChar, 16);
if (digit == -1) {
throw new IllegalArgumentException("Invalid Hexadecimal Character: " + hexChar);
}
return digit;
}
private String byteToHex(final byte num) {
final char[] hexDigits = new char[2];
hexDigits[0] = Character.forDigit((num >> 4) & 0xF, 16);
hexDigits[1] = Character.forDigit((num & 0xF), 16);
return new String(hexDigits);
}
private boolean compareHashes(final byte[] originalHash, final byte[] comparisonHash) {
int diff = originalHash.length ^ comparisonHash.length;
for (int i = 0; i < originalHash.length && i < comparisonHash.length; i++) {
diff |= originalHash[i] ^ comparisonHash[i];
}
return diff == 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy