package cipher import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/json" "errors" "io" "os" "path/filepath" ) const ( obrimCipherAlgorithm = "AES-256" obrimCipherSignature = "OBRIMCIPHER" obrimCipherVersion = "1" obrimCipherSaltSize = 32 obrimCipherNonceSize = 12 ) type ObrimCipherConfig struct { Key string `json:"key"` Input string `json:"input"` Output string `json:"output"` } type obrimCipherResponse struct { Status bool `json:"status"` Code string `json:"code"` Payload interface{} `json:"payload"` } type obrimCipherStandardPayload struct { Operation string `json:"operation"` Algorithm string `json:"algorithm"` InputPath string `json:"inputPath"` OutputPath string `json:"outputPath"` } type obrimCipherSaltedPayload struct { Operation string `json:"operation"` Algorithm string `json:"algorithm"` Format string `json:"format"` Version string `json:"version"` InputPath string `json:"inputPath"` OutputPath string `json:"outputPath"` } // ObrimCipher executes encryption or decryption workflows. func ObrimCipher(operationType string, config ObrimCipherConfig) ([]byte, error) { if err := obrimCipherValidateType(operationType); err != nil { return obrimCipherBuildResponse(false, "FAILED_INVALID_TYPE", nil) } if err := obrimCipherValidateConfig(config); err != nil { return obrimCipherBuildResponse(false, "FAILED_INVALID_CONFIG", nil) } if err := obrimCipherValidateKey(config.Key); err != nil { return obrimCipherBuildResponse(false, "FAILED_INVALID_KEY", nil) } inputPath, err := obrimCipherResolvePath(config.Input) if err != nil { return obrimCipherBuildResponse(false, "FAILED_INVALID_INPUT_PATH", nil) } outputPath, err := obrimCipherResolvePath(config.Output) if err != nil { return obrimCipherBuildResponse(false, "FAILED_INVALID_OUTPUT_PATH", nil) } inputData, err := obrimCipherReadInput(inputPath) if err != nil { return obrimCipherBuildResponse(false, "FAILED_INPUT_ACCESS", nil) } var outputData []byte switch operationType { case "encrypt-standard": outputData, err = obrimCipherEncryptStandard(inputData, config.Key) case "encrypt-salted": outputData, err = obrimCipherEncryptSalted(inputData, config.Key) case "decrypt-standard": outputData, err = obrimCipherDecryptStandard(inputData, config.Key) case "decrypt-salted": outputData, err = obrimCipherDecryptSalted(inputData, config.Key) } if err != nil { switch operationType { case "encrypt-standard", "encrypt-salted": return obrimCipherBuildResponse(false, "FAILED_ENCRYPTION", nil) case "decrypt-standard", "decrypt-salted": return obrimCipherBuildResponse(false, "FAILED_DECRYPTION", nil) } } if err := obrimCipherWriteOutput(outputPath, outputData); err != nil { return obrimCipherBuildResponse(false, "FAILED_OUTPUT_WRITE", nil) } switch operationType { case "encrypt-standard": return obrimCipherBuildResponse( true, "SUCCESS_ENCRYPT_STANDARD", obrimCipherStandardPayload{ Operation: operationType, Algorithm: obrimCipherAlgorithm, InputPath: inputPath, OutputPath: outputPath, }, ) case "decrypt-standard": return obrimCipherBuildResponse( true, "SUCCESS_DECRYPT_STANDARD", obrimCipherStandardPayload{ Operation: operationType, Algorithm: obrimCipherAlgorithm, InputPath: inputPath, OutputPath: outputPath, }, ) case "encrypt-salted": return obrimCipherBuildResponse( true, "SUCCESS_ENCRYPT_SALTED", obrimCipherSaltedPayload{ Operation: operationType, Algorithm: obrimCipherAlgorithm, Format: obrimCipherSignature, Version: obrimCipherVersion, InputPath: inputPath, OutputPath: outputPath, }, ) case "decrypt-salted": return obrimCipherBuildResponse( true, "SUCCESS_DECRYPT_SALTED", obrimCipherSaltedPayload{ Operation: operationType, Algorithm: obrimCipherAlgorithm, Format: obrimCipherSignature, Version: obrimCipherVersion, InputPath: inputPath, OutputPath: outputPath, }, ) } return obrimCipherBuildResponse(false, "FAILED_UNKNOWN_OPERATION", nil) } // obrimCipherValidateType validates operation type. func obrimCipherValidateType(operationType string) error { switch operationType { case "encrypt-standard", "encrypt-salted", "decrypt-standard", "decrypt-salted": return nil default: return errors.New("invalid operation type") } } // obrimCipherValidateConfig validates configuration values. func obrimCipherValidateConfig(config ObrimCipherConfig) error { if config.Key == "" { return errors.New("missing key") } if config.Input == "" { return errors.New("missing input") } if config.Output == "" { return errors.New("missing output") } return nil } // obrimCipherValidateKey validates AES-256 key requirements. func obrimCipherValidateKey(key string) error { if len([]byte(key)) != 32 { return errors.New("invalid aes-256 key") } return nil } // obrimCipherResolvePath resolves paths to absolute paths. func obrimCipherResolvePath(path string) (string, error) { return filepath.Abs(path) } // obrimCipherReadInput reads source file content. func obrimCipherReadInput(path string) ([]byte, error) { return os.ReadFile(path) } // obrimCipherWriteOutput writes processed output. func obrimCipherWriteOutput(path string, data []byte) error { directory := filepath.Dir(path) if err := os.MkdirAll(directory, 0755); err != nil { return err } tempFile, err := os.CreateTemp(directory, ".obrim-cipher-*") if err != nil { return err } tempPath := tempFile.Name() defer func() { _ = tempFile.Close() }() if _, err := tempFile.Write(data); err != nil { _ = os.Remove(tempPath) return err } if err := tempFile.Sync(); err != nil { _ = os.Remove(tempPath) return err } if err := tempFile.Close(); err != nil { _ = os.Remove(tempPath) return err } return os.Rename(tempPath, path) } // obrimCipherBuildResponse builds standardized responses. func obrimCipherBuildResponse(status bool, code string, payload interface{}) ([]byte, error) { response := obrimCipherResponse{ Status: status, Code: code, Payload: payload, } result, err := json.Marshal(response) if err != nil { return nil, err } return result, nil } // obrimCipherEncryptStandard encrypts data without salt metadata. func obrimCipherEncryptStandard(data []byte, key string) ([]byte, error) { return obrimCipherEncryptAES(data, []byte(key)) } // obrimCipherGenerateSalt generates cryptographically secure salt. func obrimCipherGenerateSalt() ([]byte, error) { salt := make([]byte, obrimCipherSaltSize) if _, err := io.ReadFull(rand.Reader, salt); err != nil { return nil, err } return salt, nil } // obrimCipherBuildHeader builds encrypted file header. func obrimCipherBuildHeader() []byte { var buffer bytes.Buffer buffer.WriteString(obrimCipherSignature) buffer.WriteByte('|') buffer.WriteString(obrimCipherVersion) buffer.WriteByte('|') return buffer.Bytes() } // obrimCipherEncryptSalted encrypts data with embedded salt metadata. func obrimCipherEncryptSalted(data []byte, key string) ([]byte, error) { salt, err := obrimCipherGenerateSalt() if err != nil { return nil, err } derivedKey := sha256.Sum256(append([]byte(key), salt...)) encrypted, err := obrimCipherEncryptAES(data, derivedKey[:]) if err != nil { return nil, err } header := obrimCipherBuildHeader() result := make([]byte, 0, len(header)+len(salt)+len(encrypted)) result = append(result, header...) result = append(result, salt...) result = append(result, encrypted...) return result, nil } // obrimCipherDecryptStandard decrypts AES-256 encrypted data. func obrimCipherDecryptStandard(data []byte, key string) ([]byte, error) { return obrimCipherDecryptAES(data, []byte(key)) } // obrimCipherParseHeader parses encrypted metadata. func obrimCipherParseHeader(data []byte) (string, string, int, error) { header := []byte(obrimCipherSignature + "|" + obrimCipherVersion + "|") if len(data) < len(header) { return "", "", 0, errors.New("invalid header") } if !bytes.Equal(data[:len(header)], header) { return "", "", 0, errors.New("invalid header") } return obrimCipherSignature, obrimCipherVersion, len(header), nil } // obrimCipherExtractSalt extracts embedded salt. func obrimCipherExtractSalt(data []byte, offset int) ([]byte, error) { if len(data) < offset+obrimCipherSaltSize { return nil, errors.New("salt extraction failed") } return data[offset : offset+obrimCipherSaltSize], nil } // obrimCipherExtractPayload extracts encrypted payload. func obrimCipherExtractPayload(data []byte, offset int) ([]byte, error) { start := offset + obrimCipherSaltSize if len(data) <= start { return nil, errors.New("payload extraction failed") } return data[start:], nil } // obrimCipherDecryptSalted decrypts AES-256 encrypted data with salt metadata. func obrimCipherDecryptSalted(data []byte, key string) ([]byte, error) { _, _, offset, err := obrimCipherParseHeader(data) if err != nil { return nil, err } salt, err := obrimCipherExtractSalt(data, offset) if err != nil { return nil, err } payload, err := obrimCipherExtractPayload(data, offset) if err != nil { return nil, err } derivedKey := sha256.Sum256(append([]byte(key), salt...)) return obrimCipherDecryptAES(payload, derivedKey[:]) } // obrimCipherEncryptAES performs AES-256 GCM encryption. func obrimCipherEncryptAES(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 } nonce := make([]byte, obrimCipherNonceSize) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } encrypted := gcm.Seal(nil, nonce, data, nil) result := make([]byte, 0, len(nonce)+len(encrypted)) result = append(result, nonce...) result = append(result, encrypted...) return result, nil } // obrimCipherDecryptAES performs AES-256 GCM decryption. func obrimCipherDecryptAES(data []byte, key []byte) ([]byte, error) { if len(data) < obrimCipherNonceSize { return nil, errors.New("invalid encrypted payload") } block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := data[:obrimCipherNonceSize] payload := data[obrimCipherNonceSize:] return gcm.Open(nil, nonce, payload, nil) }