/* |-------------------------------------------------------------------------- | Cipher |-------------------------------------------------------------------------- | | Name: | - Cipher | | Purpose: | - Provide reusable AES-256 encryption and decryption capabilities | supporting standard and salted file formats through a unified | interface. | | Guidelines: | - Support only AES-256 operations. | - Preserve input immutability. | - Never expose sensitive values in error responses. | - Fail safely without producing partial output. | | Examples: | - ObrimCipher("encrypt-standard", config) | - ObrimCipher("decrypt-salted", config) | |-------------------------------------------------------------------------- */ /* |-------------------------------------------------------------------------- | Credit |-------------------------------------------------------------------------- | | Contributor: | - Rajon Ahmed | - Scionite | |-------------------------------------------------------------------------- */ package cipher import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/json" "io" "os" "path/filepath" "go/module/name/essential/external/service/helper/log" "go/module/name/essential/external/service/helper/status" ) const ( obrimCipherAlgorithm = "AES-256" obrimCipherSignature = "OBRIMCIPHER" obrimCipherVersion = "1" obrimCipherSaltSize = 32 ) type obrimCipherResponse struct { Status bool `json:"status"` Code string `json:"code"` Payload any `json:"payload"` } // Function Name: ObrimCipher // Function Purpose: Execute encryption or decryption workflows. func ObrimCipher(operationType string, config map[string]any) map[string]any { log.ObrimLog("INIT", "Cipher utility started.") if errCode := obrimCipherValidateType(operationType); errCode != "" { return obrimCipherBuildResponse(false, errCode, nil) } if errCode := obrimCipherValidateConfig(config); errCode != "" { return obrimCipherBuildResponse(false, errCode, nil) } keyValue := config["key"].(string) if errCode := obrimCipherValidateKey(keyValue); errCode != "" { return obrimCipherBuildResponse(false, errCode, nil) } inputPath, err := obrimCipherResolvePath(config["input"].(string)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_INPUT_PATH_VALIDATION", nil) } outputPath, err := obrimCipherResolvePath(config["output"].(string)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_PATH_VALIDATION", nil) } inputData, err := obrimCipherReadInput(inputPath) if err != nil { return obrimCipherBuildResponse(false, "FAILED_SOURCE_FILE_ACCESS", nil) } switch operationType { case "encrypt-standard": outputData, err := obrimCipherEncryptStandard(inputData, []byte(keyValue)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_ENCRYPTION", nil) } if err := obrimCipherWriteOutput(outputPath, outputData); err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil) } status.ObrimStatus("SUCCESS", "Encryption completed.") return obrimCipherBuildResponse(true, "SUCCESS_ENCRYPT_STANDARD", map[string]any{ "operation": operationType, "algorithm": obrimCipherAlgorithm, "inputPath": inputPath, "outputPath": outputPath, }) case "encrypt-salted": outputData, err := obrimCipherEncryptSalted(inputData, []byte(keyValue)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_ENCRYPTION", nil) } if err := obrimCipherWriteOutput(outputPath, outputData); err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil) } return obrimCipherBuildResponse(true, "SUCCESS_ENCRYPT_SALTED", map[string]any{ "operation": operationType, "algorithm": obrimCipherAlgorithm, "format": obrimCipherSignature, "version": obrimCipherVersion, "inputPath": inputPath, "outputPath": outputPath, }) case "decrypt-standard": outputData, err := obrimCipherDecryptStandard(inputData, []byte(keyValue)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_DECRYPTION", nil) } if err := obrimCipherWriteOutput(outputPath, outputData); err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil) } return obrimCipherBuildResponse(true, "SUCCESS_DECRYPT_STANDARD", map[string]any{ "operation": operationType, "algorithm": obrimCipherAlgorithm, "inputPath": inputPath, "outputPath": outputPath, }) case "decrypt-salted": signature, version, err := obrimCipherParseHeader(inputData) if err != nil { return obrimCipherBuildResponse(false, "FAILED_SIGNATURE_VALIDATION", nil) } outputData, err := obrimCipherDecryptSalted(inputData, []byte(keyValue)) if err != nil { return obrimCipherBuildResponse(false, "FAILED_DECRYPTION", nil) } if err := obrimCipherWriteOutput(outputPath, outputData); err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil) } return obrimCipherBuildResponse(true, "SUCCESS_DECRYPT_SALTED", map[string]any{ "operation": operationType, "algorithm": obrimCipherAlgorithm, "format": signature, "version": version, "inputPath": inputPath, "outputPath": outputPath, }) } return obrimCipherBuildResponse(false, "FAILED_OPERATION", nil) } // Function Name: obrimCipherValidateType // Function Purpose: Validate operation type selection. func obrimCipherValidateType(operationType string) string { switch operationType { case "encrypt-standard", "encrypt-salted", "decrypt-standard", "decrypt-salted": return "" default: return "FAILED_TYPE_VALIDATION" } } // Function Name: obrimCipherValidateConfig // Function Purpose: Validate configuration values. func obrimCipherValidateConfig(config map[string]any) string { if config == nil { return "FAILED_CONFIG_VALIDATION" } _, keyOK := config["key"].(string) _, inputOK := config["input"].(string) _, outputOK := config["output"].(string) if !keyOK || !inputOK || !outputOK { return "FAILED_CONFIG_VALIDATION" } return "" } // Function Name: obrimCipherValidateKey // Function Purpose: Validate AES-256 compatible key requirements. func obrimCipherValidateKey(key string) string { if len([]byte(key)) != 32 { return "FAILED_KEY_VALIDATION" } return "" } // Function Name: obrimCipherResolvePath // Function Purpose: Resolve relative paths into absolute paths. func obrimCipherResolvePath(path string) (string, error) { return filepath.Abs(path) } // Function Name: obrimCipherReadInput // Function Purpose: Read source file content. func obrimCipherReadInput(path string) ([]byte, error) { return os.ReadFile(path) } // Function Name: obrimCipherWriteOutput // Function Purpose: Write processed output to destination file. func obrimCipherWriteOutput(path string, data []byte) error { tempPath := path + ".tmp" if err := os.WriteFile(tempPath, data, 0600); err != nil { return err } return os.Rename(tempPath, path) } // Function Name: obrimCipherBuildResponse // Function Purpose: Build standardized utility responses. func obrimCipherBuildResponse(statusValue bool, code string, payload any) map[string]any { response := obrimCipherResponse{ Status: statusValue, Code: code, Payload: payload, } buffer, _ := json.Marshal(response) var result map[string]any _ = json.Unmarshal(buffer, &result) return result } // Function Name: obrimCipherEncryptStandard // Function Purpose: Encrypt data using AES-256 without salt metadata. func obrimCipherEncryptStandard(data []byte, key []byte) ([]byte, error) { return obrimCipherEncrypt(data, key) } // Function Name: obrimCipherGenerateSalt // Function Purpose: Generate a cryptographically secure random salt. func obrimCipherGenerateSalt() ([]byte, error) { salt := make([]byte, obrimCipherSaltSize) _, err := io.ReadFull(rand.Reader, salt) return salt, err } // Function Name: obrimCipherBuildHeader // Function Purpose: Build encrypted file signature and version header. func obrimCipherBuildHeader() []byte { return []byte(obrimCipherSignature + ":" + obrimCipherVersion + ":") } // Function Name: obrimCipherEncryptSalted // Function Purpose: Encrypt data using AES-256 with embedded salt metadata. func obrimCipherEncryptSalted(data []byte, key []byte) ([]byte, error) { salt, err := obrimCipherGenerateSalt() if err != nil { return nil, err } derivedKey := sha256.Sum256(append(key, salt...)) ciphertext, err := obrimCipherEncrypt(data, derivedKey[:]) if err != nil { return nil, err } output := bytes.Buffer{} output.Write(obrimCipherBuildHeader()) output.Write(salt) output.Write(ciphertext) return output.Bytes(), nil } // Function Name: obrimCipherDecryptStandard // Function Purpose: Decrypt AES-256 encrypted data without salt metadata. func obrimCipherDecryptStandard(data []byte, key []byte) ([]byte, error) { return obrimCipherDecrypt(data, key) } // Function Name: obrimCipherParseHeader // Function Purpose: Parse encrypted file signature and version metadata. func obrimCipherParseHeader(data []byte) (string, string, error) { header := obrimCipherBuildHeader() if len(data) < len(header) { return "", "", os.ErrInvalid } if !bytes.Equal(data[:len(header)], header) { return "", "", os.ErrInvalid } return obrimCipherSignature, obrimCipherVersion, nil } // Function Name: obrimCipherExtractSalt // Function Purpose: Extract embedded salt from encrypted data. func obrimCipherExtractSalt(data []byte) ([]byte, error) { headerLength := len(obrimCipherBuildHeader()) if len(data) < headerLength+obrimCipherSaltSize { return nil, os.ErrInvalid } return data[headerLength : headerLength+obrimCipherSaltSize], nil } // Function Name: obrimCipherExtractPayload // Function Purpose: Extract encrypted payload from the encrypted file. func obrimCipherExtractPayload(data []byte) ([]byte, error) { headerLength := len(obrimCipherBuildHeader()) offset := headerLength + obrimCipherSaltSize if len(data) <= offset { return nil, os.ErrInvalid } return data[offset:], nil } // Function Name: obrimCipherDecryptSalted // Function Purpose: Decrypt AES-256 encrypted data using extracted salt metadata. func obrimCipherDecryptSalted(data []byte, key []byte) ([]byte, error) { salt, err := obrimCipherExtractSalt(data) if err != nil { return nil, err } payload, err := obrimCipherExtractPayload(data) if err != nil { return nil, err } derivedKey := sha256.Sum256(append(key, salt...)) return obrimCipherDecrypt(payload, derivedKey[:]) } // Function Name: obrimCipherEncrypt // Function Purpose: Perform AES-256 GCM encryption. func obrimCipherEncrypt(data []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } // Logic: nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } ciphertext := gcm.Seal(nil, nonce, data, nil) return append(nonce, ciphertext...), nil } // Function Name: obrimCipherDecrypt // Function Purpose: Perform AES-256 GCM decryption. func obrimCipherDecrypt(data []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonceSize := gcm.NonceSize() if len(data) < nonceSize { return nil, os.ErrInvalid } nonce := data[:nonceSize] ciphertext := data[nonceSize:] return gcm.Open(nil, nonce, ciphertext, nil) }