277 lines
7.4 KiB
Go
277 lines
7.4 KiB
Go
package key
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ObrimKeyResponse represents the standardized utility response.
|
|
type ObrimKeyResponse struct {
|
|
Status bool `json:"status"`
|
|
Code string `json:"code"`
|
|
Payload map[string]any `json:"payload"`
|
|
}
|
|
|
|
// obrimKeyAllowedSymmetricFields defines allowed symmetric configuration fields.
|
|
var obrimKeyAllowedSymmetricFields = map[string]struct{}{
|
|
"algorithm": {},
|
|
"key_size": {},
|
|
}
|
|
|
|
// obrimKeyAllowedAsymmetricFields defines allowed asymmetric configuration fields.
|
|
var obrimKeyAllowedAsymmetricFields = map[string]struct{}{
|
|
"algorithm": {},
|
|
}
|
|
|
|
// ObrimKey dispatches key generation requests and orchestrates validation, generation, and response construction.
|
|
func ObrimKey(keyType string, config map[string]any) map[string]any {
|
|
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_MISSING_TYPE")
|
|
}
|
|
|
|
if config == nil {
|
|
return obrimKeyBuildError("FAILED_MISSING_CONFIG")
|
|
}
|
|
|
|
normalizedType := strings.ToLower(strings.TrimSpace(keyType))
|
|
|
|
switch normalizedType {
|
|
case "symmetric":
|
|
return obrimKeyValidateSymmetricConfig(config)
|
|
|
|
case "asymmetric":
|
|
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 {
|
|
switch strings.ToLower(strings.TrimSpace(keyType)) {
|
|
case "symmetric":
|
|
return obrimKeyGenerateSymmetric(config)
|
|
|
|
case "asymmetric":
|
|
return obrimKeyGenerateAsymmetric(config)
|
|
|
|
default:
|
|
return obrimKeyBuildError("FAILED_UNSUPPORTED_TYPE")
|
|
}
|
|
}
|
|
|
|
// obrimKeyValidateSymmetricConfig validates symmetric configuration values.
|
|
func obrimKeyValidateSymmetricConfig(config map[string]any) map[string]any {
|
|
for field := range config {
|
|
if _, exists := obrimKeyAllowedSymmetricFields[field]; !exists {
|
|
return obrimKeyBuildError("FAILED_INVALID_CONFIG_FIELD")
|
|
}
|
|
}
|
|
|
|
algorithmValue, exists := config["algorithm"]
|
|
if !exists {
|
|
return obrimKeyBuildError("FAILED_MISSING_ALGORITHM")
|
|
}
|
|
|
|
algorithm, ok := algorithmValue.(string)
|
|
if !ok {
|
|
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
|
|
}
|
|
|
|
if strings.ToLower(strings.TrimSpace(algorithm)) != "aes" {
|
|
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
|
|
}
|
|
|
|
keySizeValue, exists := config["key_size"]
|
|
if !exists {
|
|
return obrimKeyBuildError("FAILED_MISSING_KEY_SIZE")
|
|
}
|
|
|
|
keySize, ok := obrimKeyConvertInt(keySizeValue)
|
|
if !ok {
|
|
return obrimKeyBuildError("FAILED_INVALID_KEY_SIZE")
|
|
}
|
|
|
|
switch keySize {
|
|
case 128, 192, 256:
|
|
return nil
|
|
default:
|
|
return obrimKeyBuildError("FAILED_UNSUPPORTED_KEY_SIZE")
|
|
}
|
|
}
|
|
|
|
// obrimKeyValidateAsymmetricConfig validates asymmetric configuration values.
|
|
func obrimKeyValidateAsymmetricConfig(config map[string]any) map[string]any {
|
|
for field := range config {
|
|
if _, exists := obrimKeyAllowedAsymmetricFields[field]; !exists {
|
|
return obrimKeyBuildError("FAILED_INVALID_CONFIG_FIELD")
|
|
}
|
|
}
|
|
|
|
algorithmValue, exists := config["algorithm"]
|
|
if !exists {
|
|
return obrimKeyBuildError("FAILED_MISSING_ALGORITHM")
|
|
}
|
|
|
|
algorithm, ok := algorithmValue.(string)
|
|
if !ok {
|
|
return obrimKeyBuildError("FAILED_INVALID_ALGORITHM")
|
|
}
|
|
|
|
if strings.ToLower(strings.TrimSpace(algorithm)) != "ecc" {
|
|
return obrimKeyBuildError("FAILED_UNSUPPORTED_ALGORITHM")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// obrimKeyGenerateSymmetric generates symmetric key material.
|
|
func obrimKeyGenerateSymmetric(config map[string]any) map[string]any {
|
|
normalizedConfig := obrimKeyNormalizeSymmetricConfig(config)
|
|
|
|
payload, errorCode := obrimKeyGenerateAES(normalizedConfig)
|
|
if errorCode != "" {
|
|
return obrimKeyBuildError(errorCode)
|
|
}
|
|
|
|
return obrimKeyBuildPayload(payload)
|
|
}
|
|
|
|
// obrimKeyGenerateAES generates AES key material.
|
|
func obrimKeyGenerateAES(config map[string]any) (map[string]any, string) {
|
|
keySize := config["key_size"].(int)
|
|
|
|
// obrimKeyMaterial stores generated AES key bytes.
|
|
keyMaterial := make([]byte, keySize/8)
|
|
|
|
if _, err := rand.Read(keyMaterial); err != nil {
|
|
return nil, "FAILED_KEY_GENERATION"
|
|
}
|
|
|
|
if _, err := aes.NewCipher(keyMaterial); err != nil {
|
|
return nil, "FAILED_KEY_GENERATION"
|
|
}
|
|
|
|
return map[string]any{
|
|
"type": "symmetric",
|
|
"algorithm": "aes",
|
|
"key_size": keySize,
|
|
"key_material": base64.StdEncoding.EncodeToString(keyMaterial),
|
|
"generated_at": time.Now().UTC().Format(time.RFC3339),
|
|
}, ""
|
|
}
|
|
|
|
// obrimKeyNormalizeSymmetricConfig normalizes symmetric configuration values.
|
|
func obrimKeyNormalizeSymmetricConfig(config map[string]any) map[string]any {
|
|
keySize, _ := obrimKeyConvertInt(config["key_size"])
|
|
|
|
return map[string]any{
|
|
"algorithm": strings.ToLower(strings.TrimSpace(config["algorithm"].(string))),
|
|
"key_size": keySize,
|
|
}
|
|
}
|
|
|
|
// obrimKeyGenerateAsymmetric generates asymmetric key material.
|
|
func obrimKeyGenerateAsymmetric(config map[string]any) map[string]any {
|
|
normalizedConfig := obrimKeyNormalizeAsymmetricConfig(config)
|
|
|
|
payload, errorCode := obrimKeyGenerateECC(normalizedConfig)
|
|
if errorCode != "" {
|
|
return obrimKeyBuildError(errorCode)
|
|
}
|
|
|
|
return obrimKeyBuildPayload(payload)
|
|
}
|
|
|
|
// obrimKeyGenerateECC generates ECC key pair material.
|
|
func obrimKeyGenerateECC(config map[string]any) (map[string]any, string) {
|
|
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return nil, "FAILED_KEY_GENERATION"
|
|
}
|
|
|
|
return map[string]any{
|
|
"type": "asymmetric",
|
|
"algorithm": "ecc",
|
|
"curve": "eddsa",
|
|
"public_key": base64.StdEncoding.EncodeToString(publicKey),
|
|
"private_key": base64.StdEncoding.EncodeToString(privateKey),
|
|
"generated_at": time.Now().UTC().Format(time.RFC3339),
|
|
}, ""
|
|
}
|
|
|
|
// obrimKeyNormalizeAsymmetricConfig normalizes asymmetric configuration values.
|
|
func obrimKeyNormalizeAsymmetricConfig(config map[string]any) map[string]any {
|
|
return map[string]any{
|
|
"algorithm": strings.ToLower(strings.TrimSpace(config["algorithm"].(string))),
|
|
}
|
|
}
|
|
|
|
// obrimKeyBuildPayload constructs standardized success payloads.
|
|
func obrimKeyBuildPayload(payload map[string]any) map[string]any {
|
|
return map[string]any{
|
|
"status": true,
|
|
"code": "SUCCESS_KEY_GENERATED",
|
|
"payload": payload,
|
|
}
|
|
}
|
|
|
|
// obrimKeyBuildError constructs standardized error responses.
|
|
func obrimKeyBuildError(code string) map[string]any {
|
|
return map[string]any{
|
|
"status": false,
|
|
"code": code,
|
|
"payload": nil,
|
|
}
|
|
}
|
|
|
|
// obrimKeyConvertInt converts supported numeric values to int.
|
|
func obrimKeyConvertInt(value any) (int, bool) {
|
|
switch converted := value.(type) {
|
|
case int:
|
|
return converted, true
|
|
case int8:
|
|
return int(converted), true
|
|
case int16:
|
|
return int(converted), true
|
|
case int32:
|
|
return int(converted), true
|
|
case int64:
|
|
return int(converted), true
|
|
case uint:
|
|
return int(converted), true
|
|
case uint8:
|
|
return int(converted), true
|
|
case uint16:
|
|
return int(converted), true
|
|
case uint32:
|
|
return int(converted), true
|
|
case uint64:
|
|
return int(converted), true
|
|
case float32:
|
|
if float32(int(converted)) == converted {
|
|
return int(converted), true
|
|
}
|
|
case float64:
|
|
if float64(int(converted)) == converted {
|
|
return int(converted), true
|
|
}
|
|
}
|
|
|
|
return 0, false
|
|
}
|