obrimbaseapi/essential/visible/service/helper/hash/hash.go

508 lines
10 KiB
Go

/*
|--------------------------------------------------------------------------
| Manifest
|--------------------------------------------------------------------------
|
| Name:
| - Hash
|
| Purpose:
| - Generate and verify cryptographic hash values using standard or
| salted hashing methods.
|
| Guideline:
| - Use for deterministic hashing workflows.
| - Use for salted hashing workflows requiring verification support.
| - Use for integrity verification and fingerprint generation.
| - Accept exactly two primary parameters: type and config.
|
| Example:
| - ObrimHash("calculate", config)
| - ObrimHash("compare", config)
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Credit
|--------------------------------------------------------------------------
|
| Contributor:
| - Rajon Ahmed
| - Scionite
|
|--------------------------------------------------------------------------
*/
package hash
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"strings"
"go/module/essential/visible/service/helper/log"
"go/module/essential/visible/service/helper/retriever"
"go/module/essential/visible/service/helper/status"
)
// ObrimHash processes hash generation and verification requests.
func ObrimHash(
hashType string,
config map[string]any,
) map[string]any {
status.ObrimStatus("INFO", "Hash utility execution started.")
log.ObrimLog("INIT", "Hash utility execution started.")
_, _ = retriever.ObrimRetriever(
"json",
map[string]any{
"resource": "framework/metadata",
"path": "name",
},
)
if !obrimHashValidateType(hashType) {
status.ObrimStatus("ERROR", "Invalid hash type.")
log.ObrimLog("ERROR", "Invalid hash type.")
return obrimHashBuildErrorPayload("FAILED_INVALID_TYPE")
}
if !obrimHashValidateConfig(hashType, config) {
status.ObrimStatus("ERROR", "Invalid configuration.")
log.ObrimLog("ERROR", "Invalid configuration.")
return obrimHashBuildErrorPayload("FAILED_INVALID_CONFIG")
}
mode := config["mode"].(string)
if !obrimHashValidateMode(mode) {
status.ObrimStatus("ERROR", "Invalid mode.")
log.ObrimLog("ERROR", "Invalid mode.")
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
}
algorithm := config["algorithm"].(string)
if !obrimHashValidateAlgorithm(mode, algorithm) {
status.ObrimStatus("ERROR", "Invalid algorithm.")
log.ObrimLog("ERROR", "Invalid algorithm.")
return obrimHashBuildErrorPayload("FAILED_INVALID_ALGORITHM")
}
switch hashType {
case "calculate":
return obrimHashCalculate(config)
case "compare":
return obrimHashCompare(config)
default:
return obrimHashBuildErrorPayload("FAILED_INVALID_TYPE")
}
}
// obrimHashValidateType validates operation type.
func obrimHashValidateType(hashType string) bool {
switch hashType {
case "calculate", "compare":
return true
default:
return false
}
}
// obrimHashValidateMode validates hashing mode.
func obrimHashValidateMode(mode string) bool {
switch mode {
case "standard", "salted":
return true
default:
return false
}
}
// obrimHashValidateConfig validates configuration keys and values.
func obrimHashValidateConfig(
hashType string,
config map[string]any,
) bool {
if config == nil {
return false
}
// Mutable variable holding supported keys.
supportedKeys := map[string]bool{
"mode": true,
"algorithm": true,
"value": true,
"hash": true,
"salt": true,
}
for key := range config {
if !supportedKeys[key] {
return false
}
}
modeValue, modeExists := config["mode"]
algorithmValue, algorithmExists := config["algorithm"]
valueValue, valueExists := config["value"]
if !modeExists || !algorithmExists || !valueExists {
return false
}
mode, modeOK := modeValue.(string)
algorithm, algorithmOK := algorithmValue.(string)
value, valueOK := valueValue.(string)
if !modeOK || !algorithmOK || !valueOK {
return false
}
if mode == "" || algorithm == "" || value == "" {
return false
}
if hashType == "calculate" {
if mode == "standard" {
if _, exists := config["salt"]; exists {
return false
}
}
return true
}
if hashType == "compare" {
hashValue, hashExists := config["hash"]
if !hashExists {
return false
}
hashString, hashOK := hashValue.(string)
if !hashOK || hashString == "" {
return false
}
if mode == "standard" {
if _, exists := config["salt"]; exists {
return false
}
}
if mode == "salted" {
saltValue, saltExists := config["salt"]
if !saltExists {
return false
}
saltString, saltOK := saltValue.(string)
if !saltOK || saltString == "" {
return false
}
}
return true
}
return false
}
// obrimHashValidateAlgorithm validates hashing algorithm selection.
func obrimHashValidateAlgorithm(
mode string,
algorithm string,
) bool {
if mode == "standard" {
switch algorithm {
case "sha256", "sha512":
return true
}
}
if mode == "salted" {
switch algorithm {
case "salted_sha256", "salted_sha512":
return true
}
}
return false
}
// obrimHashGenerateHash executes the selected hashing algorithm.
func obrimHashGenerateHash(
algorithm string,
value string,
salt string,
) (string, bool) {
switch algorithm {
case "sha256":
sum := sha256.Sum256([]byte(value))
return hex.EncodeToString(sum[:]), true
case "sha512":
sum := sha512.Sum512([]byte(value))
return hex.EncodeToString(sum[:]), true
case "salted_sha256":
sum := sha256.Sum256([]byte(value + salt))
return hex.EncodeToString(sum[:]), true
case "salted_sha512":
sum := sha512.Sum512([]byte(value + salt))
return hex.EncodeToString(sum[:]), true
default:
return "", false
}
}
// obrimHashBuildSuccessPayload constructs success response payloads.
func obrimHashBuildSuccessPayload(
code string,
payload map[string]any,
) map[string]any {
return map[string]any{
"status": true,
"code": code,
"payload": payload,
}
}
// obrimHashBuildErrorPayload constructs error response payloads.
func obrimHashBuildErrorPayload(code string) map[string]any {
return map[string]any{
"status": false,
"code": code,
"payload": nil,
}
}
// obrimHashCalculate processes hash generation requests.
func obrimHashCalculate(
config map[string]any,
) map[string]any {
mode := config["mode"].(string)
switch mode {
case "standard":
return obrimHashCalculateStandard(config)
case "salted":
return obrimHashCalculateSalted(config)
default:
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
}
}
// obrimHashCalculateStandard generates a deterministic hash.
func obrimHashCalculateStandard(
config map[string]any,
) map[string]any {
algorithm := config["algorithm"].(string)
value := config["value"].(string)
hashValue, success := obrimHashGenerateHash(
algorithm,
value,
"",
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
payload := map[string]any{
"algorithm": algorithm,
"hash": hashValue,
}
status.ObrimStatus("SUCCESS", "Hash generated.")
log.ObrimLog("SUCCESS", "Standard hash generated.")
return obrimHashBuildSuccessPayload(
"SUCCESS_CALCULATE_STANDARD",
payload,
)
}
// obrimHashCalculateSalted generates a salted hash and salt pair.
func obrimHashCalculateSalted(
config map[string]any,
) map[string]any {
algorithm := config["algorithm"].(string)
value := config["value"].(string)
// Mutable variable holding salt value.
saltValue := ""
if suppliedSalt, exists := config["salt"]; exists {
saltString, ok := suppliedSalt.(string)
if !ok || saltString == "" {
return obrimHashBuildErrorPayload("FAILED_INVALID_SALT")
}
saltValue = saltString
} else {
generatedSalt, success := obrimHashGenerateSalt()
if !success {
return obrimHashBuildErrorPayload("FAILED_SALT_GENERATION")
}
saltValue = generatedSalt
}
hashValue, success := obrimHashGenerateHash(
algorithm,
value,
saltValue,
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
payload := map[string]any{
"algorithm": algorithm,
"hash": hashValue,
"salt": saltValue,
}
status.ObrimStatus("SUCCESS", "Salted hash generated.")
log.ObrimLog("SUCCESS", "Salted hash generated.")
return obrimHashBuildSuccessPayload(
"SUCCESS_CALCULATE_SALTED",
payload,
)
}
// obrimHashGenerateSalt generates a cryptographically secure salt.
func obrimHashGenerateSalt() (string, bool) {
// Mutable variable holding salt bytes.
saltBytes := make([]byte, 32)
_, err := rand.Read(saltBytes)
if err != nil {
return "", false
}
return hex.EncodeToString(saltBytes), true
}
// obrimHashCompare processes hash verification requests.
func obrimHashCompare(
config map[string]any,
) map[string]any {
mode := config["mode"].(string)
switch mode {
case "standard":
return obrimHashCompareStandard(config)
case "salted":
return obrimHashCompareSalted(config)
default:
return obrimHashBuildErrorPayload("FAILED_INVALID_MODE")
}
}
// obrimHashCompareStandard regenerates a standard hash for verification.
func obrimHashCompareStandard(
config map[string]any,
) map[string]any {
algorithm := config["algorithm"].(string)
value := config["value"].(string)
hashValue := config["hash"].(string)
regeneratedHash, success := obrimHashGenerateHash(
algorithm,
value,
"",
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
matched := obrimHashVerify(
regeneratedHash,
hashValue,
)
payload := map[string]any{
"algorithm": algorithm,
"matched": matched,
"hash": hashValue,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_COMPARE_STANDARD",
payload,
)
}
// obrimHashCompareSalted regenerates a salted hash for verification.
func obrimHashCompareSalted(
config map[string]any,
) map[string]any {
algorithm := config["algorithm"].(string)
value := config["value"].(string)
hashValue := config["hash"].(string)
saltValue := config["salt"].(string)
regeneratedHash, success := obrimHashGenerateHash(
algorithm,
value,
saltValue,
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
matched := obrimHashVerify(
regeneratedHash,
hashValue,
)
payload := map[string]any{
"algorithm": algorithm,
"matched": matched,
"hash": hashValue,
"salt": saltValue,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_COMPARE_SALTED",
payload,
)
}
// obrimHashVerify compares regenerated and supplied hash values.
func obrimHashVerify(
regeneratedHash string,
suppliedHash string,
) bool {
return strings.Compare(
regeneratedHash,
suppliedHash,
) == 0
}