/* |-------------------------------------------------------------------------- | Description |-------------------------------------------------------------------------- | | Name: | - Key | | Purpose: | - Generate cryptographic key material through a type-driven dispatch | model supporting symmetric and asymmetric key generation. | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Instruction |-------------------------------------------------------------------------- | | Guideline: | - Use the utility to generate cryptographically secure symmetric or | asymmetric key material. | - Use the "symmetric" type with the supported AES algorithm and | 128, 192, or 256 bit key sizes. | - Use the "asymmetric" type with the supported ECC algorithm using | the EdDSA curve. | - Provide the type-specific configuration required for the selected | key generation workflow. | | Example: | - ObrimKey("symmetric", map[string]any{ | "algorithm": "aes", | "key_size": 256, | }) | | - ObrimKey("asymmetric", map[string]any{ | "algorithm": "ecc", | }) | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Credit |-------------------------------------------------------------------------- | | Contributor: | - Rajon Ahmed | - Blockonite | |-------------------------------------------------------------------------- */ package key import ( "crypto/aes" "crypto/ed25519" "crypto/rand" "encoding/base64" "time" ) const ( obrimKeyTypeSymmetric = "symmetric" obrimKeyTypeAsymmetric = "asymmetric" obrimKeyAlgorithmAES = "aes" obrimKeyAlgorithmECC = "ecc" obrimKeyCurveEdDSA = "eddsa" obrimKeySize128 = 128 obrimKeySize192 = 192 obrimKeySize256 = 256 ) const ( obrimKeySuccessSymmetricGenerated = "SUCCESS_SYMMETRIC_KEY_GENERATED" obrimKeySuccessAsymmetricGenerated = "SUCCESS_ASYMMETRIC_KEY_GENERATED" obrimKeyFailureInvalidType = "FAILURE_INVALID_TYPE" obrimKeyFailureInvalidConfig = "FAILURE_INVALID_CONFIG" obrimKeyFailureMissingAlgorithm = "FAILURE_MISSING_ALGORITHM" obrimKeyFailureInvalidAlgorithm = "FAILURE_INVALID_ALGORITHM" obrimKeyFailureMissingKeySize = "FAILURE_MISSING_KEY_SIZE" obrimKeyFailureInvalidKeySize = "FAILURE_INVALID_KEY_SIZE" obrimKeyFailureKeyGeneration = "FAILURE_KEY_GENERATION" obrimKeyFailureAsymmetricKeyGeneration = "FAILURE_ASYMMETRIC_KEY_GENERATION" obrimKeyFailureUnsupportedOperation = "FAILURE_UNSUPPORTED_OPERATION" ) const ( obrimKeyConfigAlgorithm = "algorithm" obrimKeyConfigKeySize = "key_size" ) type obrimKeySymmetricConfig struct { algorithm string keySize int } type obrimKeyAsymmetricConfig struct { algorithm string } type obrimKeySymmetricPayload struct { Type string `json:"type"` Algorithm string `json:"algorithm"` KeySize int `json:"key_size"` KeyMaterial string `json:"key_material"` GeneratedAt string `json:"generated_at"` } type obrimKeyAsymmetricPayload struct { Type string `json:"type"` Algorithm string `json:"algorithm"` Curve string `json:"curve"` PublicKey string `json:"public_key"` PrivateKey string `json:"private_key"` GeneratedAt string `json:"generated_at"` } type obrimKeyOutput struct { Status bool `json:"status"` Code string `json:"code"` Payload any `json:"payload"` } func ObrimKey(keyType string, config map[string]any) map[string]any { if code := obrimKeyValidateInput(keyType, config); code != "" { return obrimKeyBuildOutput(false, code, nil) } return obrimKeyRouteRequest(keyType, config) } func obrimKeyValidateInput(keyType string, config map[string]any) string { switch keyType { case obrimKeyTypeSymmetric: if config == nil { return obrimKeyFailureInvalidConfig } algorithm, ok := config[obrimKeyConfigAlgorithm] if !ok { return obrimKeyFailureMissingAlgorithm } algorithmValue, ok := algorithm.(string) if !ok || algorithmValue == "" { return obrimKeyFailureInvalidAlgorithm } switch algorithmValue { case obrimKeyAlgorithmAES: default: return obrimKeyFailureInvalidAlgorithm } keySize, ok := config[obrimKeyConfigKeySize] if !ok { return obrimKeyFailureMissingKeySize } switch value := keySize.(type) { case int: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case int8: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case int16: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case int32: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case int64: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case uint: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case uint8: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case uint16: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case uint32: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } case uint64: switch value { case obrimKeySize128, obrimKeySize192, obrimKeySize256: default: return obrimKeyFailureInvalidKeySize } default: return obrimKeyFailureInvalidKeySize } case obrimKeyTypeAsymmetric: if config == nil { return obrimKeyFailureInvalidConfig } algorithm, ok := config[obrimKeyConfigAlgorithm] if !ok { return obrimKeyFailureMissingAlgorithm } algorithmValue, ok := algorithm.(string) if !ok || algorithmValue == "" { return obrimKeyFailureInvalidAlgorithm } switch algorithmValue { case obrimKeyAlgorithmECC: default: return obrimKeyFailureInvalidAlgorithm } default: return obrimKeyFailureInvalidType } return "" } func obrimKeyRouteRequest(keyType string, config map[string]any) map[string]any { switch keyType { case obrimKeyTypeSymmetric: normalized, code := obrimKeyNormalizeSymmetricConfig(config) if code != "" { return obrimKeyBuildOutput(false, code, nil) } payload, code := obrimKeyGenerateSymmetric(normalized) if code != "" { return obrimKeyBuildOutput(false, code, nil) } return obrimKeyBuildOutput( true, obrimKeySuccessSymmetricGenerated, payload, ) case obrimKeyTypeAsymmetric: normalized, code := obrimKeyNormalizeAsymmetricConfig(config) if code != "" { return obrimKeyBuildOutput(false, code, nil) } payload, code := obrimKeyGenerateAsymmetric(normalized) if code != "" { return obrimKeyBuildOutput(false, code, nil) } return obrimKeyBuildOutput( true, obrimKeySuccessAsymmetricGenerated, payload, ) default: return obrimKeyBuildOutput(false, obrimKeyFailureUnsupportedOperation, nil) } } func obrimKeyBuildOutput(status bool, code string, payload any) map[string]any { output := obrimKeyOutput{ Status: status, Code: code, Payload: payload, } return map[string]any{ "status": output.Status, "code": output.Code, "payload": output.Payload, } } func obrimKeyNormalizeSymmetricConfig(config map[string]any) (obrimKeySymmetricConfig, string) { algorithm, ok := config[obrimKeyConfigAlgorithm].(string) if !ok || algorithm == "" { return obrimKeySymmetricConfig{}, obrimKeyFailureInvalidAlgorithm } keySizeValue, ok := config[obrimKeyConfigKeySize] if !ok { return obrimKeySymmetricConfig{}, obrimKeyFailureMissingKeySize } keySize, ok := obrimKeyNormalizeKeySize(keySizeValue) if !ok { return obrimKeySymmetricConfig{}, obrimKeyFailureInvalidKeySize } return obrimKeySymmetricConfig{ algorithm: algorithm, keySize: keySize, }, "" } func obrimKeyNormalizeKeySize(value any) (int, bool) { switch keySize := value.(type) { case int: return keySize, true case int8: return int(keySize), true case int16: return int(keySize), true case int32: return int(keySize), true case int64: return int(keySize), true case uint: return int(keySize), true case uint8: return int(keySize), true case uint16: return int(keySize), true case uint32: return int(keySize), true case uint64: return int(keySize), true default: return 0, false } } func obrimKeyGenerateSymmetric(config obrimKeySymmetricConfig) (map[string]any, string) { switch config.algorithm { case obrimKeyAlgorithmAES: return obrimKeyGenerateAES(config.keySize) default: return nil, obrimKeyFailureInvalidAlgorithm } } func obrimKeyGenerateAES(keySize int) (map[string]any, string) { keyLength := keySize / 8 keyMaterial := make([]byte, keyLength) if _, err := rand.Read(keyMaterial); err != nil { return nil, obrimKeyFailureKeyGeneration } if _, err := aes.NewCipher(keyMaterial); err != nil { return nil, obrimKeyFailureKeyGeneration } payload := obrimKeySymmetricPayload{ Type: obrimKeyTypeSymmetric, Algorithm: obrimKeyAlgorithmAES, KeySize: keySize, KeyMaterial: base64.StdEncoding.EncodeToString(keyMaterial), GeneratedAt: time.Now().UTC().Format(time.RFC3339Nano), } return map[string]any{ "type": payload.Type, "algorithm": payload.Algorithm, "key_size": payload.KeySize, "key_material": payload.KeyMaterial, "generated_at": payload.GeneratedAt, }, "" } func obrimKeyNormalizeAsymmetricConfig(config map[string]any) (obrimKeyAsymmetricConfig, string) { algorithm, ok := config[obrimKeyConfigAlgorithm].(string) if !ok || algorithm == "" { return obrimKeyAsymmetricConfig{}, obrimKeyFailureInvalidAlgorithm } return obrimKeyAsymmetricConfig{ algorithm: algorithm, }, "" } func obrimKeyGenerateAsymmetric(config obrimKeyAsymmetricConfig) (map[string]any, string) { switch config.algorithm { case obrimKeyAlgorithmECC: return obrimKeyGenerateECC() default: return nil, obrimKeyFailureInvalidAlgorithm } } func obrimKeyGenerateECC() (map[string]any, string) { publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, obrimKeyFailureAsymmetricKeyGeneration } payload := obrimKeyAsymmetricPayload{ Type: obrimKeyTypeAsymmetric, Algorithm: obrimKeyAlgorithmECC, Curve: obrimKeyCurveEdDSA, PublicKey: base64.StdEncoding.EncodeToString(publicKey), PrivateKey: base64.StdEncoding.EncodeToString(privateKey), GeneratedAt: time.Now().UTC().Format(time.RFC3339Nano), } return map[string]any{ "type": payload.Type, "algorithm": payload.Algorithm, "curve": payload.Curve, "public_key": payload.PublicKey, "private_key": payload.PrivateKey, "generated_at": payload.GeneratedAt, }, "" }