aviortui/essential/visible/service/helper/hash/hash.go
2026-08-28 12:54:31 +08:00

397 lines
10 KiB
Go

/*
|--------------------------------------------------------------------------
| Description
|--------------------------------------------------------------------------
|
| Name:
| - Hash
|
| Purpose:
| - Generate and verify cryptographic hash values using standard or
| salted hashing methods for integrity verification, canonical
| fingerprinting, resource identification, comparison workflows,
| and security-oriented hashing requirements.
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Instruction
|--------------------------------------------------------------------------
|
| Guideline:
| - Use to generate deterministic hashes in standard mode.
| - Use to generate salted hashes when salted hashing is required.
| - Use to verify supplied hash values against input values.
| - Use standard mode when deterministic hashing without a salt is
| required.
| - Use salted mode when a supplied or cryptographically secure
| generated salt is required.
|
| Example:
| - ObrimHash("calculate", map[string]any{
| "mode": "standard",
| "algorithm": "...",
| "value": "...",
| })
|
| - ObrimHash("calculate", map[string]any{
| "mode": "salted",
| "algorithm": "...",
| "value": "...",
| "salt": "...",
| })
|
| - ObrimHash("compare", map[string]any{
| "mode": "standard",
| "algorithm": "...",
| "value": "...",
| "hash": "...",
| })
|
| - ObrimHash("compare", map[string]any{
| "mode": "salted",
| "algorithm": "...",
| "value": "...",
| "hash": "...",
| "salt": "...",
| })
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Credit
|--------------------------------------------------------------------------
|
| Contributor:
| - Rajon Ahmed
| - Blockonite
|
|--------------------------------------------------------------------------
*/
package hash
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"errors"
"hash"
)
// Hash result codes.
const (
ObrimHashSuccessCalculated = "SUCCESS_CALCULATED"
ObrimHashSuccessCompared = "SUCCESS_COMPARED"
ObrimHashFailureInvalidType = "FAILURE_INVALID_TYPE"
ObrimHashFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
ObrimHashFailureInvalidMode = "FAILURE_INVALID_MODE"
ObrimHashFailureInvalidAlgorithm = "FAILURE_INVALID_ALGORITHM"
ObrimHashFailureInvalidValue = "FAILURE_INVALID_VALUE"
ObrimHashFailureInvalidHash = "FAILURE_INVALID_HASH"
ObrimHashFailureInvalidSalt = "FAILURE_INVALID_SALT"
ObrimHashFailureProcessing = "FAILURE_PROCESSING"
)
// Hash utility modes.
const (
obrimHashModeStandard = "standard"
obrimHashModeSalted = "salted"
)
// Hash utility algorithms.
const (
obrimHashAlgorithmSHA256 = "sha256"
obrimHashAlgorithmSHA512 = "sha512"
)
// Hash utility configuration keys.
const (
obrimHashConfigMode = "mode"
obrimHashConfigAlgorithm = "algorithm"
obrimHashConfigValue = "value"
obrimHashConfigHash = "hash"
obrimHashConfigSalt = "salt"
)
// Hash utility operation types.
const (
obrimHashTypeCalculate = "calculate"
obrimHashTypeCompare = "compare"
)
// Hash utility output structure.
type obrimHashOutput struct {
Status bool `json:"status"`
Code string `json:"code"`
Payload map[string]any `json:"payload"`
}
// Hash utility request configuration.
type obrimHashConfig struct {
Mode string
Algorithm string
Value string
Hash string
Salt string
}
// Hash utility execution function.
func ObrimHash(Type string, Config map[string]any) map[string]any {
ConfigData, Code := obrimHashValidateInput(Type, Config)
if Code != "" {
return obrimHashBuildOutput(false, Code, nil)
}
return obrimHashRouteRequest(Type, ConfigData)
}
// Validate hash utility input.
func obrimHashValidateInput(Type string, Config map[string]any) (obrimHashConfig, string) {
var ConfigData obrimHashConfig
switch Type {
case obrimHashTypeCalculate, obrimHashTypeCompare:
default:
return ConfigData, ObrimHashFailureInvalidType
}
if Config == nil {
return ConfigData, ObrimHashFailureInvalidConfig
}
ConfigData.Mode = obrimHashReadStringConfig(Config, obrimHashConfigMode)
ConfigData.Algorithm = obrimHashReadStringConfig(Config, obrimHashConfigAlgorithm)
ConfigData.Value = obrimHashReadStringConfig(Config, obrimHashConfigValue)
ConfigData.Hash = obrimHashReadStringConfig(Config, obrimHashConfigHash)
ConfigData.Salt = obrimHashReadStringConfig(Config, obrimHashConfigSalt)
switch ConfigData.Mode {
case obrimHashModeStandard, obrimHashModeSalted:
default:
return ConfigData, ObrimHashFailureInvalidMode
}
switch ConfigData.Algorithm {
case obrimHashAlgorithmSHA256, obrimHashAlgorithmSHA512:
default:
return ConfigData, ObrimHashFailureInvalidAlgorithm
}
if ConfigData.Value == "" {
return ConfigData, ObrimHashFailureInvalidValue
}
switch Type {
case obrimHashTypeCalculate:
if ConfigData.Mode == obrimHashModeStandard && ConfigData.Salt != "" {
return ConfigData, ObrimHashFailureInvalidSalt
}
case obrimHashTypeCompare:
if ConfigData.Hash == "" {
return ConfigData, ObrimHashFailureInvalidHash
}
switch ConfigData.Mode {
case obrimHashModeStandard:
if ConfigData.Salt != "" {
return ConfigData, ObrimHashFailureInvalidSalt
}
case obrimHashModeSalted:
if ConfigData.Salt == "" {
return ConfigData, ObrimHashFailureInvalidSalt
}
}
}
return ConfigData, ""
}
// Route the hash utility request.
func obrimHashRouteRequest(Type string, Config obrimHashConfig) map[string]any {
switch Type {
case obrimHashTypeCalculate:
return obrimHashCalculate(Config)
case obrimHashTypeCompare:
return obrimHashCompare(Config)
default:
return obrimHashBuildOutput(false, ObrimHashFailureInvalidType, nil)
}
}
// Build standardized hash utility output.
func obrimHashBuildOutput(Status bool, Code string, Payload map[string]any) map[string]any {
Output := obrimHashOutput{
Status: Status,
Code: Code,
Payload: Payload,
}
return map[string]any{
"status": Output.Status,
"code": Output.Code,
"payload": Output.Payload,
}
}
// Process hash generation.
func obrimHashCalculate(Config obrimHashConfig) map[string]any {
switch Config.Mode {
case obrimHashModeStandard:
return obrimHashCalculateStandard(Config)
case obrimHashModeSalted:
return obrimHashCalculateSalted(Config)
default:
return obrimHashBuildOutput(false, ObrimHashFailureInvalidMode, nil)
}
}
// Generate deterministic standard hash.
func obrimHashCalculateStandard(Config obrimHashConfig) map[string]any {
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Value)
if Error != nil {
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
}
Payload := map[string]any{
"algorithm": Config.Algorithm,
"hash": HashValue,
}
return obrimHashBuildOutput(true, ObrimHashSuccessCalculated, Payload)
}
// Generate salted hash.
func obrimHashCalculateSalted(Config obrimHashConfig) map[string]any {
Salt := Config.Salt
if Salt == "" {
var Error error
Salt, Error = obrimHashGenerateSalt()
if Error != nil {
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
}
}
HashValue, Error := obrimHashGenerate(Config.Algorithm, Salt+Config.Value)
if Error != nil {
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
}
Payload := map[string]any{
"algorithm": Config.Algorithm,
"hash": HashValue,
"salt": Salt,
}
return obrimHashBuildOutput(true, ObrimHashSuccessCalculated, Payload)
}
// Generate a cryptographically secure random salt.
func obrimHashGenerateSalt() (string, error) {
Salt := make([]byte, 32)
if _, Error := rand.Read(Salt); Error != nil {
return "", Error
}
return hex.EncodeToString(Salt), nil
}
// Process hash verification.
func obrimHashCompare(Config obrimHashConfig) map[string]any {
switch Config.Mode {
case obrimHashModeStandard:
return obrimHashCompareStandard(Config)
case obrimHashModeSalted:
return obrimHashCompareSalted(Config)
default:
return obrimHashBuildOutput(false, ObrimHashFailureInvalidMode, nil)
}
}
// Verify standard hash.
func obrimHashCompareStandard(Config obrimHashConfig) map[string]any {
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Value)
if Error != nil {
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
}
Matched := obrimHashVerify(HashValue, Config.Hash)
Payload := map[string]any{
"algorithm": Config.Algorithm,
"matched": Matched,
"hash": Config.Hash,
}
return obrimHashBuildOutput(true, ObrimHashSuccessCompared, Payload)
}
// Verify salted hash.
func obrimHashCompareSalted(Config obrimHashConfig) map[string]any {
HashValue, Error := obrimHashGenerate(Config.Algorithm, Config.Salt+Config.Value)
if Error != nil {
return obrimHashBuildOutput(false, ObrimHashFailureProcessing, nil)
}
Matched := obrimHashVerify(HashValue, Config.Hash)
Payload := map[string]any{
"algorithm": Config.Algorithm,
"matched": Matched,
"hash": Config.Hash,
"salt": Config.Salt,
}
return obrimHashBuildOutput(true, ObrimHashSuccessCompared, Payload)
}
// Verify regenerated and supplied hashes using strict byte comparison.
func obrimHashVerify(Expected string, Supplied string) bool {
return string([]byte(Expected)) == string([]byte(Supplied))
}
// Generate a hash using the selected algorithm.
func obrimHashGenerate(Algorithm string, Value string) (string, error) {
var HashFunction func() hash.Hash
switch Algorithm {
case obrimHashAlgorithmSHA256:
HashFunction = sha256.New
case obrimHashAlgorithmSHA512:
HashFunction = sha512.New
default:
return "", errors.New("unsupported hashing algorithm")
}
Hasher := HashFunction()
if _, Error := Hasher.Write([]byte(Value)); Error != nil {
return "", Error
}
return hex.EncodeToString(Hasher.Sum(nil)), nil
}
// Read a string configuration value.
func obrimHashReadStringConfig(Config map[string]any, Key string) string {
Value, Exists := Config[Key]
if !Exists || Value == nil {
return ""
}
StringValue, Valid := Value.(string)
if !Valid {
return ""
}
return StringValue
}