413 lines
9.8 KiB
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,
|
|
}
|
|
}
|