func (o *DecryptOptions) Decrypt() error { // Get PEM data block var data []byte switch { case len(o.EncryptedFile) > 0: if d, err := ioutil.ReadFile(o.EncryptedFile); err != nil { return err } else { data = d } case len(o.EncryptedData) > 0: data = o.EncryptedData case o.EncryptedReader != nil && !term.IsTerminalReader(o.EncryptedReader): if d, err := ioutil.ReadAll(o.EncryptedReader); err != nil { return err } else { data = d } } if len(data) == 0 { return fmt.Errorf("no input data specified") } dataBlock, ok := pemutil.BlockFromBytes(data, configapi.StringSourceEncryptedBlockType) if !ok { return fmt.Errorf("input does not contain a valid PEM block of type %q", configapi.StringSourceEncryptedBlockType) } // Get password keyBlock, ok, err := pemutil.BlockFromFile(o.KeyFile, configapi.StringSourceKeyBlockType) if err != nil { return err } if !ok { return fmt.Errorf("%s does not contain a valid PEM block of type %q", o.KeyFile, configapi.StringSourceKeyBlockType) } if len(keyBlock.Bytes) == 0 { return fmt.Errorf("%s does not contain a key", o.KeyFile) } password := keyBlock.Bytes // Decrypt plaintext, err := x509.DecryptPEMBlock(dataBlock, password) if err != nil { return err } // Write decrypted data switch { case len(o.DecryptedFile) > 0: if err := ioutil.WriteFile(o.DecryptedFile, plaintext, os.FileMode(0600)); err != nil { return err } case o.DecryptedWriter != nil: fmt.Fprint(o.DecryptedWriter, string(plaintext)) if term.IsTerminalWriter(o.DecryptedWriter) { fmt.Fprintln(o.DecryptedWriter) } } return nil }
func (o *EncryptOptions) Encrypt() error { // Get data var data []byte var warnWhitespace = true switch { case len(o.CleartextFile) > 0: if d, err := ioutil.ReadFile(o.CleartextFile); err != nil { return err } else { data = d } case len(o.CleartextData) > 0: // Don't warn in cases where we're explicitly being given the data to use warnWhitespace = false data = o.CleartextData case o.CleartextReader != nil && term.IsTerminalReader(o.CleartextReader) && o.PromptWriter != nil: // Read a single line from stdin with prompting data = []byte(term.PromptForString(o.CleartextReader, o.PromptWriter, "Data to encrypt: ")) case o.CleartextReader != nil: // Read data from stdin without prompting (allows binary data and piping) if d, err := ioutil.ReadAll(o.CleartextReader); err != nil { return err } else { data = d } } if warnWhitespace && (o.PromptWriter != nil) && (len(data) > 0) { r1, _ := utf8.DecodeRune(data) r2, _ := utf8.DecodeLastRune(data) if unicode.IsSpace(r1) || unicode.IsSpace(r2) { fmt.Fprintln(o.PromptWriter, "Warning: Data includes leading or trailing whitespace, which will be included in the encrypted value") } } // Get key var key []byte switch { case len(o.KeyFile) > 0: if block, ok, err := pemutil.BlockFromFile(o.KeyFile, configapi.StringSourceKeyBlockType); err != nil { return err } else if !ok { return fmt.Errorf("%s does not contain a valid PEM block of type %q", o.KeyFile, configapi.StringSourceKeyBlockType) } else if len(block.Bytes) == 0 { return fmt.Errorf("%s does not contain a key", o.KeyFile) } else { key = block.Bytes } case len(o.GenKeyFile) > 0: key = make([]byte, 32) if _, err := rand.Read(key); err != nil { return err } } if len(key) == 0 { return errors.New("--genkey or --key is required") } // Encrypt dataBlock, err := x509.EncryptPEMBlock(rand.Reader, configapi.StringSourceEncryptedBlockType, data, key, x509.PEMCipherAES256) if err != nil { return err } // Write data if len(o.EncryptedFile) > 0 { if err := pemutil.BlockToFile(o.EncryptedFile, dataBlock, os.FileMode(0644)); err != nil { return err } } else if o.EncryptedWriter != nil { encryptedBytes, err := pemutil.BlockToBytes(dataBlock) if err != nil { return err } n, err := o.EncryptedWriter.Write(encryptedBytes) if err != nil { return err } if n != len(encryptedBytes) { return fmt.Errorf("could not completely write encrypted data") } } // Write key if len(o.GenKeyFile) > 0 { keyBlock := &pem.Block{Bytes: key, Type: configapi.StringSourceKeyBlockType} if err := pemutil.BlockToFile(o.GenKeyFile, keyBlock, os.FileMode(0600)); err != nil { return err } } return nil }
func (o *DecryptOptions) Validate(args []string) error { if len(args) != 0 { return errors.New("no arguments are supported") } if len(o.EncryptedFile) == 0 && len(o.EncryptedData) == 0 && (o.EncryptedReader == nil || term.IsTerminalReader(o.EncryptedReader)) { return errors.New("no input data specified") } if len(o.EncryptedFile) > 0 && len(o.EncryptedData) > 0 { return errors.New("cannot specify both an input file and data") } if len(o.KeyFile) == 0 { return errors.New("no key specified") } return nil }