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

349 lines
9.2 KiB
Go

/*
|--------------------------------------------------------------------------
| Manifest
|--------------------------------------------------------------------------
|
| Name:
| - Key
|
| Purpose:
| - Generate cryptographic key material using a type-driven dispatch model.
|
| Guideline:
| - Use explicit configuration values only.
| - Validate all inputs before generation.
| - Reject unsupported or irrelevant configuration fields.
| - Use centralized dispatch for workflow execution.
|
| Example:
| - ObrimKey("symmetric", map[string]any{
| "algorithm": "aes",
| "key_size": 256,
| })
|
| - ObrimKey("asymmetric", map[string]any{
| "algorithm": "ecc",
| })
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Credit
|--------------------------------------------------------------------------
|
| Contributor:
| - Rajon Ahmed
| - Scionite
|
|--------------------------------------------------------------------------
*/
package key
import (
"crypto/aes"
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
"time"
"go/module/essential/visible/service/helper/log"
"go/module/essential/visible/service/helper/status"
)
const (
obrimKeyTypeSymmetric = "symmetric"
obrimKeyTypeAsymmetric = "asymmetric"
obrimKeyAlgorithmAES = "aes"
obrimKeyAlgorithmECC = "ecc"
obrimKeyCurveEdDSA = "eddsa"
)
// ObrimKey dispatches key generation requests and orchestrates validation, generation, and response construction.
func ObrimKey(keyType string, config map[string]any) map[string]any {
log.ObrimLog("INIT", "Key generation request received.")
status.ObrimStatus("INFO", "Validating key generation request.")
if response := obrimKeyValidate(keyType, config); response != nil {
return response
}
return obrimKeyDispatch(keyType, config)
}
// obrimKeyValidate validates common request structure and schema integrity.
func obrimKeyValidate(keyType string, config map[string]any) map[string]any {
if strings.TrimSpace(keyType) == "" {
return obrimKeyBuildError("FAILED_TYPE_REQUIRED")
}
if config == nil {
return obrimKeyBuildError("FAILED_CONFIG_REQUIRED")
}
normalizedType := strings.ToLower(strings.TrimSpace(keyType))
switch normalizedType {
case obrimKeyTypeSymmetric:
return obrimKeyValidateSymmetricConfig(config)
case obrimKeyTypeAsymmetric:
return obrimKeyValidateAsymmetricConfig(config)
default:
return obrimKeyBuildError("FAILED_UNSUPPORTED_TYPE")
}
}
// obrimKeyDispatch routes execution to the appropriate cryptographic workflow.
func obrimKeyDispatch(keyType string, config map[string]any) map[string]any {
normalizedType := strings.ToLower(strings.TrimSpace(keyType))
switch normalizedType {
case obrimKeyTypeSymmetric:
return obrimKeyGenerateSymmetric(config)
case obrimKeyTypeAsymmetric:
return obrimKeyGenerateAsymmetric(config)
default:
return obrimKeyBuildError("FAILED_UNSUPPORTED_TYPE")
}
}
// obrimKeyValidateSymmetricConfig validates symmetric configuration values.
func obrimKeyValidateSymmetricConfig(config map[string]any) map[string]any {
if len(config) != 2 {
return obrimKeyBuildError("FAILED_INVALID_CONFIGURATION")
}
for key := range config {
if key != "algorithm" && key != "key_size" {
return obrimKeyBuildError("FAILED_UNSUPPORTED_CONFIGURATION_FIELD")
}
}
algorithmValue, exists := config["algorithm"]
if !exists {
return obrimKeyBuildError("FAILED_ALGORITHM_REQUIRED")
}
algorithm, ok := algorithmValue.(string)
if !ok {
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
}
normalizedConfig := obrimKeyNormalizeSymmetricConfig(config)
if strings.ToLower(strings.TrimSpace(algorithm)) != obrimKeyAlgorithmAES {
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
}
keySizeValue, exists := normalizedConfig["key_size"]
if !exists {
return obrimKeyBuildError("FAILED_KEY_SIZE_REQUIRED")
}
keySize, ok := keySizeValue.(int)
if !ok {
return obrimKeyBuildError("FAILED_INVALID_KEY_SIZE")
}
if keySize != 128 && keySize != 192 && keySize != 256 {
return obrimKeyBuildError("FAILED_UNSUPPORTED_KEY_SIZE")
}
return nil
}
// obrimKeyValidateAsymmetricConfig validates asymmetric configuration values.
func obrimKeyValidateAsymmetricConfig(config map[string]any) map[string]any {
if len(config) != 1 {
return obrimKeyBuildError("FAILED_INVALID_CONFIGURATION")
}
for key := range config {
if key != "algorithm" {
return obrimKeyBuildError("FAILED_UNSUPPORTED_CONFIGURATION_FIELD")
}
}
algorithmValue, exists := config["algorithm"]
if !exists {
return obrimKeyBuildError("FAILED_ALGORITHM_REQUIRED")
}
algorithm, ok := algorithmValue.(string)
if !ok {
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
}
if strings.ToLower(strings.TrimSpace(algorithm)) != obrimKeyAlgorithmECC {
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
}
return nil
}
// obrimKeyGenerateSymmetric generates symmetric key material.
func obrimKeyGenerateSymmetric(config map[string]any) map[string]any {
log.ObrimLog("INIT", "Generating symmetric key material.")
normalizedConfig := obrimKeyNormalizeSymmetricConfig(config)
payload, err := obrimKeyGenerateAES(normalizedConfig)
if err != nil {
log.ObrimLog("ERROR", err.Error())
return obrimKeyBuildError("FAILED_KEY_GENERATION")
}
log.ObrimLog("SUCCESS", "Symmetric key material generated.")
status.ObrimStatus("SUCCESS", "Key generation completed.")
return map[string]any{
"status": true,
"code": "SUCCESS_KEY_GENERATED",
"payload": payload,
}
}
// obrimKeyGenerateAES generates AES key material.
func obrimKeyGenerateAES(config map[string]any) (map[string]any, error) {
// Mutable variable holding key size.
keySize := config["key_size"].(int)
// Mutable variable holding key bytes.
keyBytes := make([]byte, keySize/8)
if _, err := rand.Read(keyBytes); err != nil {
return nil, err
}
if _, err := aes.NewCipher(keyBytes); err != nil {
return nil, err
}
payload := map[string]any{
"type": obrimKeyTypeSymmetric,
"algorithm": obrimKeyAlgorithmAES,
"key_size": keySize,
"key_material": base64.StdEncoding.EncodeToString(keyBytes),
"generated_at": time.Now().UTC().Format(time.RFC3339),
}
return payload, nil
}
// obrimKeyNormalizeSymmetricConfig normalizes symmetric configuration values.
func obrimKeyNormalizeSymmetricConfig(config map[string]any) map[string]any {
normalized := map[string]any{}
if value, exists := config["algorithm"]; exists {
if algorithm, ok := value.(string); ok {
normalized["algorithm"] = strings.ToLower(strings.TrimSpace(algorithm))
}
}
if value, exists := config["key_size"]; exists {
switch typed := value.(type) {
case int:
normalized["key_size"] = typed
case int8:
normalized["key_size"] = int(typed)
case int16:
normalized["key_size"] = int(typed)
case int32:
normalized["key_size"] = int(typed)
case int64:
normalized["key_size"] = int(typed)
case float32:
normalized["key_size"] = int(typed)
case float64:
normalized["key_size"] = int(typed)
}
}
return normalized
}
// obrimKeyGenerateAsymmetric generates asymmetric key material.
func obrimKeyGenerateAsymmetric(config map[string]any) map[string]any {
log.ObrimLog("INIT", "Generating asymmetric key material.")
normalizedConfig := obrimKeyNormalizeAsymmetricConfig(config)
payload, err := obrimKeyGenerateECC(normalizedConfig)
if err != nil {
log.ObrimLog("ERROR", err.Error())
return obrimKeyBuildError("FAILED_KEY_GENERATION")
}
log.ObrimLog("SUCCESS", "Asymmetric key material generated.")
status.ObrimStatus("SUCCESS", "Key generation completed.")
return map[string]any{
"status": true,
"code": "SUCCESS_KEY_GENERATED",
"payload": payload,
}
}
// obrimKeyGenerateECC generates ECC key pair material.
func obrimKeyGenerateECC(config map[string]any) (map[string]any, error) {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
payload := map[string]any{
"type": obrimKeyTypeAsymmetric,
"algorithm": obrimKeyAlgorithmECC,
"curve": obrimKeyCurveEdDSA,
"public_key": base64.StdEncoding.EncodeToString(publicKey),
"private_key": base64.StdEncoding.EncodeToString(privateKey),
"generated_at": time.Now().UTC().Format(time.RFC3339),
}
return payload, nil
}
// obrimKeyNormalizeAsymmetricConfig normalizes asymmetric configuration values.
func obrimKeyNormalizeAsymmetricConfig(config map[string]any) map[string]any {
normalized := map[string]any{}
if value, exists := config["algorithm"]; exists {
if algorithm, ok := value.(string); ok {
normalized["algorithm"] = strings.ToLower(strings.TrimSpace(algorithm))
}
}
return normalized
}
// obrimKeyBuildPayload constructs standardized success payloads.
func obrimKeyBuildPayload(payload map[string]any) map[string]any {
return map[string]any{
"status": true,
"code": "SUCCESS",
"payload": payload,
}
}
// obrimKeyBuildError constructs standardized error responses.
func obrimKeyBuildError(code string) map[string]any {
log.ObrimLog("ERROR", fmt.Sprintf("Key generation failed: %s", code))
status.ObrimStatus("ERROR", code)
return map[string]any{
"status": false,
"code": code,
"payload": nil,
}
}