diff --git a/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/CryptoUtil.java b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/CryptoUtil.java index 8e28961..cf42471 100644 --- a/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/CryptoUtil.java +++ b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/CryptoUtil.java @@ -22,6 +22,12 @@ package com.onixbyte.crypto.util; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + /** * Utility class for cryptographic operations. * @@ -57,6 +63,36 @@ public final class CryptoUtil { return pemKeyText .replaceAll("-----BEGIN ((EC )|(RSA ))?(PRIVATE|PUBLIC) KEY-----", "") .replaceAll("-----END ((EC )|(RSA ))?(PRIVATE|PUBLIC) KEY-----", "") - .replaceAll("\n", ""); + .replace("\n", ""); + } + + /** + * Computes a Hash-based Message Authentication Code (HMAC) using the SHA-256 algorithm. + *
+ * The input payload and secret key are both processed using the {@code UTF-8} charset + * to guarantee consistent results across different operating system environments. + * The final byte array output is converted into a lower-case hexadecimal string. + * + * @param payload the raw string data or message content to be authenticated + * @param secret the secret key used to sign the payload + * @return a lower-case hexadecimal string representing the computed HMAC-SHA256 signature + * @throws NoSuchAlgorithmException if the HmacSHA256 algorithm is not available in the environment + * @throws InvalidKeyException if the provided secret key is inappropriate for + * initialising the MAC + */ + public static String hmacSha256( + String payload, + String secret + ) throws NoSuchAlgorithmException, InvalidKeyException { + var secretKeySpec = new SecretKeySpec( + secret.getBytes(StandardCharsets.UTF_8), + "HmacSHA256" + ); + + var mac = Mac.getInstance("HmacSHA256"); + mac.init(secretKeySpec); + + var rawHmac = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8)); + return EncodingUtil.bytesToHex(rawHmac); } } diff --git a/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/EncodingUtil.java b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/EncodingUtil.java new file mode 100644 index 0000000..b105409 --- /dev/null +++ b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/EncodingUtil.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024-2026 OnixByte + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.onixbyte.crypto.util; + +import java.util.HexFormat; + +/** + * Utility class for handling various data encoding and formatting operations. + *
+ * This class provides helper methods to convert raw binary data into standardised + * string representations (such as hexadecimal format) commonly required for + * cryptographic verification, logging, and data transmission. + *
+ * This utility class is stateless and thread-safe. + * + * @author siujamo + */ +public class EncodingUtil { + + /** + * Converts an array of bytes into its corresponding hexadecimal string representation. + *
+ * Each byte is converted to a two-digit hex string. If the resulting hex value + * is a single digit (i.e., less than 16), a leading '0' is automatically prepended + * to ensure a consistent and uniform format throughout the output string. + * + * @param bytes the byte array to be converted, typically the raw output of a cryptographic hash + * @return a lower-case hexadecimal string representing the input bytes + */ + public static String bytesToHex(byte[] bytes) { + return HexFormat.of().formatHex(bytes); + } +} diff --git a/common-toolbox/src/main/java/com/onixbyte/common/util/HashUtil.java b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/HashUtil.java similarity index 99% rename from common-toolbox/src/main/java/com/onixbyte/common/util/HashUtil.java rename to crypto-toolbox/src/main/java/com/onixbyte/crypto/util/HashUtil.java index 5d5aa96..e1edfc0 100644 --- a/common-toolbox/src/main/java/com/onixbyte/common/util/HashUtil.java +++ b/crypto-toolbox/src/main/java/com/onixbyte/crypto/util/HashUtil.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package com.onixbyte.common.util; +package com.onixbyte.crypto.util; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -66,7 +66,7 @@ import java.util.Optional; * * @author zihluwang * @version 3.0.0 - * @see java.security.MessageDigest + * @see MessageDigest */ public final class HashUtil {