Skip to content

Commit

Permalink
adding byte flags for keytype in lib. password policy, command aliase…
Browse files Browse the repository at this point in the history
…s and prefix for key and ciphertext in CLI.
  • Loading branch information
shibme committed Jan 20, 2024
1 parent 4cdedf5 commit a4c7406
Show file tree
Hide file tree
Showing 18 changed files with 397 additions and 534 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ nfpms:
brews:
- name: xipher
homepage: "https://dev.shib.me/xipher"
description: "Xipher is a curated collection of cryptographic primitives written in Go to encrypt and decrypt data with optional compression."
description: "Xipher is a curated collection of cryptographic primitives put together to perform password-based asymmetric encryption. It is written in Go and can be used as a library or a CLI tool."
license: "MIT"
commit_author:
name: Shibly Meeran
Expand Down
56 changes: 31 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
[![Release Status](https://github.com/shibme/xipher/actions/workflows/release.yml/badge.svg)](https://github.com/shibme/xipher/actions/workflows/release.yml)
[![License](https://img.shields.io/github/license/shibme/xipher)](https://github.com/shibme/xipher/blob/main/LICENSE)

Xipher is a curated collection of cryptographic primitives written in Go to encrypt and decrypt data with optional compression.
Xipher is a curated collection of cryptographic primitives put together to perform password-based asymmetric encryption. It is written in Go and can be used as a library or a CLI tool.

### Features
- Password based public key generation.
- Encrypt data with public key generated from a password.
- Encrypt data with password or a generated private key.
- Decrypt data with password or a a given private key (works on all combinations of encryption).
- Encryption of data with the public key generated from a password.
- Supports stream cipher along with stream compression thereby keeping a low memory footprint. Makes it handy for encrypting large files or data streams.

### Under the hood
Expand All @@ -21,12 +19,38 @@ Xipher uses the following cryptographic primitives and libraries to encrypt/decr
- [XChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305) for encryption and decryption.
- [Zlib](https://en.wikipedia.org/wiki/Zlib) for compression and decompression.

### Install or Update
```bash
### CLI

#### Install/Update (CLI)
Download the latest binary from the [releases](https://github.com/shibme/xipher/releases/latest) page and add it to your path.

You can also install with brew using the following command
```sh
brew install shibme/beta/xipher
```
Alternatively try it out using docker
```sh
docker run --rm -v $(pwd):/data/ -it shibme/xipher help
```

#### Usage Example (CLI)
- Generate a new public key
```sh
xipher keygen
```
- Use the public key to encrypt text/file
```sh
xipher encrypt text -k <public_key>
```

### Go Package

#### Install/Update (Go Package)
```sh
go get -u dev.shib.me/xipher
```

### Usage Example
#### Usage Example (Go Package)
```go
package main

Expand Down Expand Up @@ -67,22 +91,4 @@ func main() {
}
fmt.Println("Decrypted:", string(plainText))
}
```
The output of the above code looks something like this:
```sh
PublicKey: MS5JUG7ZVJLETJA7WE2XKFHRE4PP6LKYCTEF2FTNUJ5QEZJIGZPCAIABX7UMDM7DPZX6WNOXICBUBBPPKE
Encrypted: AQQCAAN75DA3HY36N7VTLV2AQNAIL32RBWA2GJY7JNFA7QNOBT4CFXFBZMKY36DGE6FBKPATB7EJTD5SCNXI6URGO4WERYXYHYTL4RCXLRMYBG4K4UDZ5HGE7APXUVZ4RNESUV3EWVDJBHUAT5F7U5BFNUMTXB72Q3AZBGZDN3KXBWLUX23Q
Decrypted: Hello World!
```

### Basic CLI
Download the latest binary from the [releases](https://github.com/shibme/xipher/releases/latest) page and add it to your path.

You can also install with brew using the following command
```sh
brew install shibme/beta/xipher
```
Alternatively try it out using docker by mounting to `/data` directory inside the container
```sh
docker run --rm -v $(pwd):/data/ -it shibme/xipher help
```
28 changes: 15 additions & 13 deletions cli/internal/commands/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package commands
import "github.com/spf13/cobra"

const (
appName = "xipher"
appName = "xipher"
xipherKeyPrefix = "XK_"
xipherTxtPrefix = "XT_"
)

var (
Expand All @@ -20,7 +22,7 @@ var (
encryptCmd *cobra.Command

// Encrypt String Command
encryptStrCmd *cobra.Command
encryptTxtCmd *cobra.Command

// Encrypt File Command
encryptFileCmd *cobra.Command
Expand All @@ -29,7 +31,7 @@ var (
decryptCmd *cobra.Command

// Decrypt String Command
decryptStrCmd *cobra.Command
decryptTxtCmd *cobra.Command

// Decrypt File Command
decryptFileCmd *cobra.Command
Expand All @@ -50,11 +52,11 @@ var (
usage: "Shows version info",
}

// Password Flag
passwordFlag = flagDef{
name: "password",
shorthand: "p",
usage: "Specify a password",
// Ignore Password Policy Check Flag
ignorePasswordCheckFlag = flagDef{
name: "ignore",
shorthand: "i",
usage: "Ignores the password policy check",
}

// Key Flag
Expand All @@ -64,11 +66,11 @@ var (
usage: "Specify a key string",
}

// String Flag
stringFlag = flagDef{
name: "string",
shorthand: "s",
usage: "Specify a string",
// Ciphertext Flag
ciphertextFlag = flagDef{
name: "ciphertext",
shorthand: "c",
usage: "Specify the ciphertext",
}

// File Flag
Expand Down
126 changes: 50 additions & 76 deletions cli/internal/commands/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,86 +6,78 @@ import (
"os"

"dev.shib.me/xipher"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

func fromXipherText(xipherText string) ([]byte, error) {
if len(xipherText) < len(xipherTxtPrefix) || xipherText[:len(xipherTxtPrefix)] != xipherTxtPrefix {
return nil, fmt.Errorf("invalid xipher text")
}
return decode(xipherText[len(xipherTxtPrefix):])
}

func decryptCommand() *cobra.Command {
if decryptCmd != nil {
return decryptCmd
}
decryptCmd = &cobra.Command{
Use: "decrypt",
Short: "Decrypts the data",
Use: "decrypt",
Aliases: []string{"decr", "dec", "de", "d"},
Short: "Decrypts the encrypted data",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}
decryptCmd.AddCommand(decryptStringCommand())
decryptCmd.AddCommand(decryptTextCommand())
decryptCmd.AddCommand(decryptFileCommand())
return decryptCmd
}

func decryptStringCommand() *cobra.Command {
if decryptStrCmd != nil {
return decryptStrCmd
func decryptTextCommand() *cobra.Command {
if decryptTxtCmd != nil {
return decryptTxtCmd
}
decryptStrCmd = &cobra.Command{
Use: "string",
Aliases: []string{"str"},
Short: "Decrypts a xipher encrypted string",
decryptTxtCmd = &cobra.Command{
Use: "text",
Aliases: []string{"txt", "t", "string", "str", "s"},
Short: "Decrypts a xipher encrypted text",
Run: func(cmd *cobra.Command, args []string) {
cipheredStr, err := decode(cmd.Flag(stringFlag.name).Value.String())
xipherText, err := fromXipherText(cmd.Flag(ciphertextFlag.name).Value.String())
if err != nil {
exitOnError(err)
}
var src, dst bytes.Buffer
src.Write(cipheredStr)
keyStr := cmd.Flag(keyFlag.name).Value.String()
if keyStr != "" {
keyBytes, err := decode(keyStr)
if err != nil {
exitOnError(err)
}
privKey, err := xipher.ParsePrivateKey(keyBytes)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(&dst, &src)
if err != nil {
exitOnError(err)
}
} else {
// Get password from user
password, err := getPasswordFromUser(false)
if err != nil {
exitOnError(err)
}
privKey, err := xipher.NewPrivateKeyForPassword(password)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(&dst, &src)
if err != nil {
exitOnError(err)
}
src.Write(xipherText)
password, err := getPasswordFromUser(false, true)
if err != nil {
exitOnError(err)
}
fmt.Println(dst.String())
privKey, err := xipher.NewPrivateKeyForPassword(password)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(&dst, &src)
if err != nil {
exitOnError(err)
}
fmt.Println(color.GreenString(dst.String()))
safeExit()
},
}
decryptStrCmd.Flags().StringP(stringFlag.name, stringFlag.shorthand, "", stringFlag.usage)
decryptStrCmd.Flags().StringP(keyFlag.name, keyFlag.shorthand, "", keyFlag.usage)
decryptStrCmd.MarkFlagRequired(stringFlag.name)
return decryptStrCmd
decryptTxtCmd.Flags().StringP(ciphertextFlag.name, ciphertextFlag.shorthand, "", ciphertextFlag.usage)
decryptTxtCmd.MarkFlagRequired(ciphertextFlag.name)
return decryptTxtCmd
}

func decryptFileCommand() *cobra.Command {
if decryptFileCmd != nil {
return decryptFileCmd
}
decryptFileCmd = &cobra.Command{
Use: "file",
Short: "Decrypts a xipher encrypted file",
Use: "file",
Aliases: []string{"f"},
Short: "Decrypts a xipher encrypted file",
Run: func(cmd *cobra.Command, args []string) {
srcPath := cmd.Flag(fileFlag.name).Value.String()
dstPath := cmd.Flag(outFlag.name).Value.String()
Expand All @@ -101,41 +93,23 @@ func decryptFileCommand() *cobra.Command {
if err != nil {
exitOnError(err)
}
keyStr := cmd.Flag(keyFlag.name).Value.String()
if keyStr != "" {
keyBytes, err := decode(keyStr)
if err != nil {
exitOnError(err)
}
privKey, err := xipher.ParsePrivateKey(keyBytes)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(dst, src)
if err != nil {
exitOnError(err)
}
} else {
// Get password from user
password, err := getPasswordFromUser(false)
if err != nil {
exitOnError(err)
}
privKey, err := xipher.NewPrivateKeyForPassword(password)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(dst, src)
if err != nil {
exitOnError(err)
}
password, err := getPasswordFromUser(false, true)
if err != nil {
exitOnError(err)
}
privKey, err := xipher.NewPrivateKeyForPassword(password)
if err != nil {
exitOnError(err)
}
err = privKey.DecryptStream(dst, src)
if err != nil {
exitOnError(err)
}
safeExit()
},
}
decryptFileCmd.Flags().StringP(fileFlag.name, fileFlag.shorthand, "", fileFlag.usage)
decryptFileCmd.Flags().StringP(outFlag.name, outFlag.shorthand, "", outFlag.usage)
decryptFileCmd.Flags().StringP(keyFlag.name, keyFlag.shorthand, "", keyFlag.usage)
decryptFileCmd.MarkFlagRequired(fileFlag.name)
decryptFileCmd.MarkFlagRequired(outFlag.name)
return decryptFileCmd
Expand Down
Loading

0 comments on commit a4c7406

Please sign in to comment.