Add RPC function for encrypting data

This commit is contained in:
2025-05-08 19:46:18 +00:00
parent d4845e53ad
commit 9d7417e26d
6 changed files with 79 additions and 38 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ RCW is a cascading symmetric cryptography agent meant to be embedded within Go p
It encrypts all data with both AES256-GCM and ChaCha20-Poly1305. It encrypts all data with both AES256-GCM and ChaCha20-Poly1305.
Passphrases are securely cached for three minutes and RPC authentication is used to Passphrases are securely cached for three minutes and RPC authentication is used to
ensure that only the binary+user responsible for caching the passphrase can retrieve it. ensure that only the binary+user responsible for caching the passphrase can utilize it.
This feature is supported on Linux, FreeBSD, MacOS, and Windows. This feature is supported on Linux, FreeBSD, MacOS, and Windows.
RCW also features a sanity check to ensure no data loss occurs due to a user entering the RCW also features a sanity check to ensure no data loss occurs due to a user entering the
+9 -2
View File
@@ -16,15 +16,22 @@ type RCWService struct{}
// DecryptRequest is the RPC method that decrypts the incoming data using // DecryptRequest is the RPC method that decrypts the incoming data using
// the global passphrase and returns the decrypted data // the global passphrase and returns the decrypted data
func (h *RCWService) DecryptRequest(request []byte, reply *[]byte) error { func (h *RCWService) DecryptRequest(encBytes []byte, reply *[]byte) error {
var err error var err error
*reply, err = wrappers.Decrypt(request, globalPassphrase) *reply, err = wrappers.Decrypt(encBytes, globalPassphrase)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
// EncryptRequest is the RPC method that encrypts the incoming data using
// the global passphrase and returns the encrypted data
func (h *RCWService) EncryptRequest(decBytes []byte, reply *[]byte) error {
*reply = wrappers.Encrypt(decBytes, globalPassphrase)
return nil
}
// getFileHash returns the SHA256 hash of the file at the given path. // getFileHash returns the SHA256 hash of the file at the given path.
func getFileHash(path string) []byte { func getFileHash(path string) []byte {
file, _ := os.Open(path) file, _ := os.Open(path)
+44 -15
View File
@@ -2,34 +2,63 @@ package daemon
import ( import (
"log" "log"
"net"
"net/rpc" "net/rpc"
) )
// CallDaemonIfOpen uses the RCW daemon (if one is available) to // DecryptWithDaemonIfOpen uses the RCW daemon (if one is available) to
// decrypt and return data. If no RCW daemon is accessible, nil is returned. // decrypt and return data. If no RCW daemon is accessible, nil is returned.
func CallDaemonIfOpen(encBytes []byte) []byte { func DecryptWithDaemonIfOpen(encBytes []byte) []byte {
if daemonIsOpen() { if daemonIsOpen() {
return call(encBytes) return getDecFromDaemon(encBytes)
} }
return nil return nil
} }
// call connects to the RPC server and requests the passphrase. // EncryptWithDaemonIfOpen uses the RCW daemon (if one is available) to
func call(encBytes []byte) []byte { // encrypt and return data. If no RCW daemon is accessible, nil is returned.
// connect to the UNIX domain socket/Windows named pipe func EncryptWithDaemonIfOpen(decBytes []byte) []byte {
conn := getConn() if daemonIsOpen() {
defer conn.Close() return getEncFromDaemon(decBytes)
}
return nil
}
// create an RPC client using the connection // getDecFromDaemon requests the RCW daemon to decrypt the given data.
client := rpc.NewClient(conn) // It returns the decrypted data.
func getDecFromDaemon(encBytes []byte) []byte {
conn, client := connectToDaemon()
defer conn.Close()
defer client.Close() defer client.Close()
// request the passphrase from the RPC server // request decBytes from the RPC server
var reply []byte var decBytes []byte
if err := client.Call("RCWService.DecryptRequest", encBytes, &reply); err != nil { if err := client.Call("RCWService.DecryptRequest", encBytes, &decBytes); err != nil {
log.Fatalf("Error calling RCWService.DecryptRequest: %v", err) log.Fatalf("Error calling RCWService.DecryptRequest: %v", err)
} }
return decBytes
}
// return the passphrase // getEncFromDaemon requests the RCW daemon to encrypt the given data.
return []byte(reply) // It returns the encrypted data.
func getEncFromDaemon(decBytes []byte) []byte {
conn, client := connectToDaemon()
defer conn.Close()
defer client.Close()
// request encBytes from the RPC server
var encBytes []byte
if err := client.Call("RCWService.EncryptRequest", decBytes, &encBytes); err != nil {
log.Fatalf("Error calling RCWService.EncryptRequest: %v", err)
}
return encBytes
}
// connectToDaemon establishes a connection to the RCW daemon.
// It returns the connection and the RPC client.
// The caller is responsible for closing the connection and client.
func connectToDaemon() (net.Conn, *rpc.Client) {
conn := getConn()
client := rpc.NewClient(conn)
return conn, client
} }
+17 -12
View File
@@ -15,7 +15,7 @@ import (
// Usage: // Usage:
// rcw init <passwd> : Generates the required sanity check file // rcw init <passwd> : Generates the required sanity check file
// rcw <passphrase> : Runs the rcw daemon to decrypt data for three minutes // rcw <passphrase> : Runs the rcw daemon to decrypt data for three minutes
// rcw enc <text> <passwd> : Encrypts the provided text and outputs the ciphertext to encrypted-example.txt // rcw enc <text> : Encrypts the provided text and outputs the ciphertext to ex-cipher.rcw (attempts to use daemon, falls back to user input for passphrase)
// rcw dec : Decrypts ex-cipher.rcw and outputs the plaintext to stdout (attempts to use daemon, falls back to user input for passphrase) // rcw dec : Decrypts ex-cipher.rcw and outputs the plaintext to stdout (attempts to use daemon, falls back to user input for passphrase)
// TODO Tests: // TODO Tests:
@@ -26,6 +26,7 @@ import (
// RPC password sharing // RPC password sharing
// TODO Enhancements: // TODO Enhancements:
// Fix sanity check (should be performed when starting the daemon to ensure the correct passphrase is used)
// Standalone cmd: // Standalone cmd:
// Usable as symmetric-only GPG replacement // Usable as symmetric-only GPG replacement
@@ -45,7 +46,7 @@ func main() {
fmt.Println(err) fmt.Println(err)
return return
} }
decBytes := daemon.CallDaemonIfOpen(encBytes) decBytes := daemon.DecryptWithDaemonIfOpen(encBytes)
if decBytes == nil { if decBytes == nil {
fmt.Println("No RCW daemon available") fmt.Println("No RCW daemon available")
passphrase := inputHidden("Enter RCW passphrase:") passphrase := inputHidden("Enter RCW passphrase:")
@@ -69,19 +70,23 @@ func main() {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
} return
case 4: } else if os.Args[1] == "enc" {
// encrypt data (from cli args) // encrypt data (using daemon if available)
// rcw enc <text> <passwd> // rcw enc <data>
err := wrappers.RunSanityCheck(sanityFile, []byte(os.Args[3])) decBytes := []byte(os.Args[2])
if err != nil { encBytes := daemon.EncryptWithDaemonIfOpen(decBytes)
fmt.Println(err) if encBytes == nil {
fmt.Println("No RCW daemon available")
passphrase := inputHidden("Enter RCW passphrase:")
encBytes = wrappers.Encrypt(decBytes, passphrase)
}
os.WriteFile(outputFile, encBytes, 0600)
return return
} }
encBytes := wrappers.Encrypt([]byte(os.Args[2]), []byte(os.Args[3])) fallthrough
os.WriteFile(outputFile, encBytes, 0600)
default: default:
fmt.Println("Usage: rcw [init <passwd>] | [enc <text> <passwd>] | dec | <passwd>") fmt.Println("Usage: rcw [init <passwd>] | [enc <text>] | dec | <passwd>")
} }
} }
+4 -4
View File
@@ -1,14 +1,14 @@
module github.com/rwinkhart/rcw module github.com/rwinkhart/rcw
go 1.24.2 go 1.24.3
require github.com/rwinkhart/peercred-mini v0.0.0-20250407033241-c09add2eceea require github.com/rwinkhart/peercred-mini v0.0.0-20250407033241-c09add2eceea
require ( require (
github.com/Microsoft/go-winio v0.6.2 github.com/Microsoft/go-winio v0.6.2
golang.org/x/crypto v0.37.0 golang.org/x/crypto v0.38.0
golang.org/x/sys v0.32.0 golang.org/x/sys v0.33.0
golang.org/x/term v0.31.0 golang.org/x/term v0.32.0
) )
replace golang.org/x/sys => github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0 replace golang.org/x/sys => github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0
+4 -4
View File
@@ -4,7 +4,7 @@ github.com/rwinkhart/peercred-mini v0.0.0-20250407033241-c09add2eceea h1:VE2ti/A
github.com/rwinkhart/peercred-mini v0.0.0-20250407033241-c09add2eceea/go.mod h1:t+YkvAdnTKTrg4d469tw3K+GCUzX/Bja4h8yKjSIsGs= github.com/rwinkhart/peercred-mini v0.0.0-20250407033241-c09add2eceea/go.mod h1:t+YkvAdnTKTrg4d469tw3K+GCUzX/Bja4h8yKjSIsGs=
github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0 h1:KRbqimv9Eexf3VB2FrRAQ4v2fGGu7gt3ayMgdT0FNao= github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0 h1:KRbqimv9Eexf3VB2FrRAQ4v2fGGu7gt3ayMgdT0FNao=
github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= github.com/rwinkhart/sys-freebsd-13-xucred v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=