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

413 lines
9.8 KiB
Go

package hash
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
)
// ObrimHashResponse represents the standard utility response structure.
type ObrimHashResponse struct {
Status bool `json:"status"`
Code string `json:"code"`
Payload interface{} `json:"payload"`
}
// ObrimHashCalculateStandardPayload represents a standard hash generation payload.
type ObrimHashCalculateStandardPayload struct {
Algorithm string `json:"algorithm"`
Hash string `json:"hash"`
}
// ObrimHashCalculateSaltedPayload represents a salted hash generation payload.
type ObrimHashCalculateSaltedPayload struct {
Algorithm string `json:"algorithm"`
Hash string `json:"hash"`
Salt string `json:"salt"`
}
// ObrimHashCompareStandardPayload represents a standard hash comparison payload.
type ObrimHashCompareStandardPayload struct {
Algorithm string `json:"algorithm"`
Matched bool `json:"matched"`
Hash string `json:"hash"`
}
// ObrimHashCompareSaltedPayload represents a salted hash comparison payload.
type ObrimHashCompareSaltedPayload struct {
Algorithm string `json:"algorithm"`
Matched bool `json:"matched"`
Hash string `json:"hash"`
Salt string `json:"salt"`
}
// ObrimHashConfig represents utility configuration.
type ObrimHashConfig struct {
Mode string
Algorithm string
Value string
Hash string
Salt string
}
// obrimHashAllowedConfigKeys defines supported configuration keys.
var obrimHashAllowedConfigKeys = map[string]struct{}{
"mode": {},
"algorithm": {},
"value": {},
"hash": {},
"salt": {},
}
// ObrimHash processes hash generation and verification requests.
func ObrimHash(hashType string, config map[string]string) ObrimHashResponse {
if response := obrimHashValidateType(hashType); response != nil {
return *response
}
if response := obrimHashValidateConfig(hashType, config); response != nil {
return *response
}
parsedConfig := ObrimHashConfig{
Mode: config["mode"],
Algorithm: config["algorithm"],
Value: config["value"],
Hash: config["hash"],
Salt: config["salt"],
}
if response := obrimHashValidateMode(parsedConfig.Mode); response != nil {
return *response
}
if response := obrimHashValidateAlgorithm(parsedConfig.Mode, parsedConfig.Algorithm); response != nil {
return *response
}
switch hashType {
case "calculate":
return obrimHashCalculate(parsedConfig)
case "compare":
return obrimHashCompare(parsedConfig)
default:
return obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_TYPE")
}
}
// obrimHashValidateType validates operation type.
func obrimHashValidateType(hashType string) *ObrimHashResponse {
switch hashType {
case "calculate", "compare":
return nil
default:
response := obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_TYPE")
return &response
}
}
// obrimHashValidateMode validates hashing mode.
func obrimHashValidateMode(mode string) *ObrimHashResponse {
switch mode {
case "standard", "salted":
return nil
default:
response := obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_MODE")
return &response
}
}
// obrimHashValidateAlgorithm validates hashing algorithm selection.
func obrimHashValidateAlgorithm(mode string, algorithm string) *ObrimHashResponse {
switch mode {
case "standard":
switch algorithm {
case "sha256", "sha512":
return nil
}
case "salted":
switch algorithm {
case "salted_sha256", "salted_sha512":
return nil
}
}
response := obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_ALGORITHM")
return &response
}
// obrimHashValidateConfig validates configuration keys and values.
func obrimHashValidateConfig(hashType string, config map[string]string) *ObrimHashResponse {
if config == nil {
response := obrimHashBuildErrorPayload("FAILED_INVALID_CONFIG")
return &response
}
for key := range config {
if _, exists := obrimHashAllowedConfigKeys[key]; !exists {
response := obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_CONFIG_KEY")
return &response
}
}
if config["mode"] == "" {
response := obrimHashBuildErrorPayload("FAILED_MISSING_MODE")
return &response
}
if config["algorithm"] == "" {
response := obrimHashBuildErrorPayload("FAILED_MISSING_ALGORITHM")
return &response
}
if config["value"] == "" {
response := obrimHashBuildErrorPayload("FAILED_EMPTY_VALUE")
return &response
}
switch hashType {
case "calculate":
if config["mode"] == "standard" && config["salt"] != "" {
response := obrimHashBuildErrorPayload("FAILED_SALT_NOT_ALLOWED")
return &response
}
case "compare":
if config["hash"] == "" {
response := obrimHashBuildErrorPayload("FAILED_EMPTY_HASH")
return &response
}
if config["mode"] == "standard" && config["salt"] != "" {
response := obrimHashBuildErrorPayload("FAILED_SALT_NOT_ALLOWED")
return &response
}
if config["mode"] == "salted" && config["salt"] == "" {
response := obrimHashBuildErrorPayload("FAILED_MISSING_SALT")
return &response
}
}
return nil
}
// obrimHashGenerateHash executes the selected hashing algorithm.
func obrimHashGenerateHash(algorithm string, value string, salt string) (string, bool) {
var input []byte
switch algorithm {
case "sha256":
input = []byte(value)
// Generate SHA-256 hash.
sum := sha256.Sum256(input)
return hex.EncodeToString(sum[:]), true
case "sha512":
input = []byte(value)
// Generate SHA-512 hash.
sum := sha512.Sum512(input)
return hex.EncodeToString(sum[:]), true
case "salted_sha256":
input = []byte(value + salt)
// Generate salted SHA-256 hash.
sum := sha256.Sum256(input)
return hex.EncodeToString(sum[:]), true
case "salted_sha512":
input = []byte(value + salt)
// Generate salted SHA-512 hash.
sum := sha512.Sum512(input)
return hex.EncodeToString(sum[:]), true
}
return "", false
}
// obrimHashCalculate processes hash generation requests.
func obrimHashCalculate(config ObrimHashConfig) ObrimHashResponse {
switch config.Mode {
case "standard":
return obrimHashCalculateStandard(config)
case "salted":
return obrimHashCalculateSalted(config)
default:
return obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_MODE")
}
}
// obrimHashCalculateStandard generates a deterministic hash.
func obrimHashCalculateStandard(config ObrimHashConfig) ObrimHashResponse {
hashValue, success := obrimHashGenerateHash(
config.Algorithm,
config.Value,
"",
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
payload := ObrimHashCalculateStandardPayload{
Algorithm: config.Algorithm,
Hash: hashValue,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_HASH_GENERATED",
payload,
)
}
// obrimHashCalculateSalted generates a salted hash and salt pair.
func obrimHashCalculateSalted(config ObrimHashConfig) ObrimHashResponse {
// Store active salt value.
activeSalt := config.Salt
if activeSalt == "" {
generatedSalt, success := obrimHashGenerateSalt()
if !success {
return obrimHashBuildErrorPayload("FAILED_SALT_GENERATION")
}
activeSalt = generatedSalt
}
hashValue, success := obrimHashGenerateHash(
config.Algorithm,
config.Value,
activeSalt,
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
payload := ObrimHashCalculateSaltedPayload{
Algorithm: config.Algorithm,
Hash: hashValue,
Salt: activeSalt,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_HASH_GENERATED",
payload,
)
}
// obrimHashGenerateSalt generates a cryptographically secure salt.
func obrimHashGenerateSalt() (string, bool) {
// Allocate random salt bytes.
saltBytes := make([]byte, 32)
if _, err := rand.Read(saltBytes); err != nil {
return "", false
}
return hex.EncodeToString(saltBytes), true
}
// obrimHashCompare processes hash verification requests.
func obrimHashCompare(config ObrimHashConfig) ObrimHashResponse {
switch config.Mode {
case "standard":
return obrimHashCompareStandard(config)
case "salted":
return obrimHashCompareSalted(config)
default:
return obrimHashBuildErrorPayload("FAILED_UNSUPPORTED_MODE")
}
}
// obrimHashCompareStandard regenerates a standard hash for verification.
func obrimHashCompareStandard(config ObrimHashConfig) ObrimHashResponse {
regeneratedHash, success := obrimHashGenerateHash(
config.Algorithm,
config.Value,
"",
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
matched := obrimHashVerify(
regeneratedHash,
config.Hash,
)
payload := ObrimHashCompareStandardPayload{
Algorithm: config.Algorithm,
Matched: matched,
Hash: config.Hash,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_HASH_COMPARED",
payload,
)
}
// obrimHashCompareSalted regenerates a salted hash for verification.
func obrimHashCompareSalted(config ObrimHashConfig) ObrimHashResponse {
regeneratedHash, success := obrimHashGenerateHash(
config.Algorithm,
config.Value,
config.Salt,
)
if !success {
return obrimHashBuildErrorPayload("FAILED_HASH_GENERATION")
}
matched := obrimHashVerify(
regeneratedHash,
config.Hash,
)
payload := ObrimHashCompareSaltedPayload{
Algorithm: config.Algorithm,
Matched: matched,
Hash: config.Hash,
Salt: config.Salt,
}
return obrimHashBuildSuccessPayload(
"SUCCESS_HASH_COMPARED",
payload,
)
}
// obrimHashVerify compares regenerated and supplied hash values.
func obrimHashVerify(regeneratedHash string, suppliedHash string) bool {
return regeneratedHash == suppliedHash
}
// obrimHashBuildSuccessPayload constructs success response payloads.
func obrimHashBuildSuccessPayload(code string, payload interface{}) ObrimHashResponse {
return ObrimHashResponse{
Status: true,
Code: code,
Payload: payload,
}
}
// obrimHashBuildErrorPayload constructs error response payloads.
func obrimHashBuildErrorPayload(code string) ObrimHashResponse {
return ObrimHashResponse{
Status: false,
Code: code,
Payload: nil,
}
}