dev.fitko.fitconnect.core.crypto.HashService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of client Show documentation
Show all versions of client Show documentation
Library that provides client access to the FIT-Connect api-endpoints for sending, subscribing and
routing
The newest version!
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;
}
}