upd: essential/file updated
helper key updated
This commit is contained in:
parent
c1172749b4
commit
14753f7d10
@ -0,0 +1,445 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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,
|
||||
}, ""
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user