Skip to content

Commit

Permalink
Problem: no encrypt and decrypt cmds for message (#1411)
Browse files Browse the repository at this point in the history
* Problem: no encrypt and decrypt cmds for message

* fix doc

* add gen

* test

* cleanup

* move command to e2ee module

move encrypt cmd to e2ee module

move decrypt cmd to e2ee

update integration test

store key as string, to make autocli better

fix integration test

Update x/e2ee/client/cli/encrypt.go

Signed-off-by: yihuang <[email protected]>

fix lint

---------

Signed-off-by: yihuang <[email protected]>
Co-authored-by: yihuang <[email protected]>
Co-authored-by: yihuang <[email protected]>
  • Loading branch information
3 people authored Apr 29, 2024
1 parent 36a6b02 commit 87efbec
Show file tree
Hide file tree
Showing 21 changed files with 458 additions and 100 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

### Features

* [#1406](https://github.com/crypto-org-chain/cronos/pull/1406) Add set-encryption-key for encryption module.
* [#1406](https://github.com/crypto-org-chain/cronos/pull/1406) Add set-encryption-key for encryption module.
* [#1411](https://github.com/crypto-org-chain/cronos/pull/1411) Add encrypt and decrypt cmds for message.

*April 8, 2024*

Expand Down
7 changes: 1 addition & 6 deletions client/docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@
}
},
{
"url": "./tmp-swagger-gen/e2ee/query.swagger.json",
"operationIds": {
"rename": {
"Params": "Keys"
}
}
"url": "./tmp-swagger-gen/e2ee/query.swagger.json"
},
{
"url": "./tmp-swagger-gen/ethermint/evm/v1/query.swagger.json",
Expand Down
2 changes: 2 additions & 0 deletions cmd/cronosd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/crypto-org-chain/cronos/v2/app"
"github.com/crypto-org-chain/cronos/v2/cmd/cronosd/opendb"
"github.com/crypto-org-chain/cronos/v2/x/cronos"
e2eecli "github.com/crypto-org-chain/cronos/v2/x/e2ee/client/cli"
// this line is used by starport scaffolding # stargate/root/import
)

Expand Down Expand Up @@ -189,6 +190,7 @@ func initRootCmd(
queryCommand(),
txCommand(),
ethermintclient.KeyCommands(app.DefaultNodeHome),
e2eecli.E2EECommand(),
)

// add rosetta
Expand Down
6 changes: 6 additions & 0 deletions gomod2nix.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ schema = 3
[mod."cosmossdk.io/x/upgrade"]
version = "v0.1.1"
hash = "sha256-bM9ybpaibMH7k4M6/QAXCZ3fJcADfJHxvMgp4AVUihs="
[mod."filippo.io/age"]
version = "v1.1.1"
hash = "sha256-LRxxJQLQkzoCNYGS/XBixVmYXoZ1mPHKvFicPGXYLcw="
[mod."filippo.io/edwards25519"]
version = "v1.1.0"
hash = "sha256-9ACANrgWZSd5HYPfDZHY8DVbPSC9LOMgy8deq3rDOoc="
Expand Down Expand Up @@ -575,6 +578,9 @@ schema = 3
[mod."github.com/tendermint/go-amino"]
version = "v0.16.0"
hash = "sha256-JW4zO/0vMzf1dXLePOqaMtiLUZgNbuIseh9GV+jQlf0="
[mod."github.com/test-go/testify"]
version = "v1.1.4"
hash = "sha256-8xygO1Rd4eTrmRe/g7zaifpNkeb6EmjNfUvTWbjDtPg="
[mod."github.com/tidwall/btree"]
version = "v0.0.0-20240406140148-2687063b042c"
hash = "sha256-8eDLGHhw4qXG6MEa7w5Q9KLwOobXr8Vn5qqyQhuipQw="
Expand Down
38 changes: 35 additions & 3 deletions integration_tests/cosmoscli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import binascii
import enum
import hashlib
import itertools
import json
import os
import re
Expand Down Expand Up @@ -1851,16 +1852,16 @@ def query_e2ee_key(self, address):
home=self.data_dir,
output="json",
)
)
)["key"]

def set_e2ee_key(self, key, **kwargs):
def register_e2ee_key(self, key, **kwargs):
kwargs.setdefault("gas_prices", DEFAULT_GAS_PRICE)
kwargs.setdefault("gas", DEFAULT_GAS)
rsp = json.loads(
self.raw(
"tx",
"e2ee",
"set-encryption-key",
"register-encryption-key",
key,
"-y",
home=self.data_dir,
Expand All @@ -1870,3 +1871,34 @@ def set_e2ee_key(self, key, **kwargs):
if rsp["code"] == 0:
rsp = self.event_query_tx_for(rsp["txhash"])
return rsp

def keygen(self, **kwargs):
return self.raw("e2ee", "keygen", home=self.data_dir, **kwargs).strip().decode()

def encrypt(self, input, *recipients, **kwargs):
return (
self.raw(
"e2ee",
"encrypt",
input,
*itertools.chain.from_iterable(("-r", r) for r in recipients),
home=self.data_dir,
**kwargs,
)
.strip()
.decode()
)

def decrypt(self, input, identity="e2ee-identity", **kwargs):
return (
self.raw(
"e2ee",
"decrypt",
input,
home=self.data_dir,
identity=identity,
**kwargs,
)
.strip()
.decode()
)
32 changes: 24 additions & 8 deletions integration_tests/test_e2ee.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import base64
def test_encrypt_decrypt(cronos):
cli = cronos.cosmos_cli()

# gen two keys for two accounts
pubkey0 = cli.keygen(keyring_name="key0")
cli.register_e2ee_key(pubkey0, _from="validator")
assert cli.query_e2ee_key(cli.address("validator")) == pubkey0
pubkey1 = cli.keygen(keyring_name="key1")
cli.register_e2ee_key(pubkey1, _from="community")
assert cli.query_e2ee_key(cli.address("community")) == pubkey1

def test_set_key(cronos):
cli = cronos.cosmos_cli()
key = base64.b64encode(b"new_key").decode("utf-8")
cli.set_e2ee_key(key, _from="community")
adr = cli.address("community")
p = cli.query_e2ee_key(adr)
assert p["key"] == key
# prepare data file to encrypt
content = "Hello World!"
plainfile = cli.data_dir / "plaintext"
plainfile.write_text(content)

cipherfile = cli.data_dir / "ciphertext"
cli.encrypt(
plainfile,
cli.address("validator"),
cli.address("community"),
output=cipherfile,
)

assert cli.decrypt(cipherfile, identity="key0") == content
assert cli.decrypt(cipherfile, identity="key1") == content
2 changes: 1 addition & 1 deletion proto/e2ee/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ option go_package = "github.com/crypto-org-chain/cronos/v2/x/e2ee/types";
// EncryptionKeyEntry is a type that contains the owner and the public key.
message EncryptionKeyEntry {
string address = 1;
bytes key = 2;
string key = 2;
}

// GenesisState defines the e2ee module's genesis state.
Expand Down
2 changes: 1 addition & 1 deletion proto/e2ee/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ message KeyRequest {

// KeyResponse is the response type for the Query/Key RPC method.
message KeyResponse {
bytes key = 1;
string key = 1;
}
2 changes: 1 addition & 1 deletion proto/e2ee/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ message MsgRegisterEncryptionKey {
option (cosmos.msg.v1.signer) = "address";

string address = 1;
bytes key = 2;
string key = 2;
}

// MsgRegisterEncryptionKeyResponse defines the Msg/RegisterEncryptionKey response type
Expand Down
4 changes: 2 additions & 2 deletions x/e2ee/autocli.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "RegisterEncryptionKey",
Use: "set-encryption-key [key]",
Short: "Set encryption key is stored associated with the user address.",
Use: "register-encryption-key [key]",
Short: "Register encryption key stores an public key for asymmetric encryption with the user address.",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "key"},
},
Expand Down
18 changes: 18 additions & 0 deletions x/e2ee/client/cli/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cli

import "github.com/spf13/cobra"

func E2EECommand() *cobra.Command {
cmd := &cobra.Command{
Use: "e2ee",
Short: "End-to-end encryption commands",
}

cmd.AddCommand(
KeygenCommand(),
EncryptCommand(),
DecryptCommand(),
)

return cmd
}
108 changes: 108 additions & 0 deletions x/e2ee/client/cli/decrypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cli

import (
"fmt"
"io"
"os"

"filippo.io/age"
"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"

"github.com/crypto-org-chain/cronos/v2/x/e2ee/keyring"
"github.com/crypto-org-chain/cronos/v2/x/e2ee/types"
)

const FlagIdentity = "identity"

func DecryptCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "decrypt [input-file]",
Short: "Decrypt input file to local identity",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

kr, err := keyring.New("cronosd", clientCtx.Keyring.Backend(), clientCtx.HomeDir, os.Stdin)
if err != nil {
return err
}

outputFile, err := cmd.Flags().GetString(flags.FlagOutput)
if err != nil {
return err
}

identityNames, err := cmd.Flags().GetStringArray(FlagIdentity)
if err != nil {
return err
}

if len(identityNames) == 0 {
return fmt.Errorf("no identity provided")
}

identities := make([]age.Identity, len(identityNames))
for i, name := range identityNames {
secret, err := kr.Get(name)
if err != nil {
return err
}

identity, err := age.ParseX25519Identity(string(secret))
if err != nil {
return err
}

identities[i] = identity
}

var input io.Reader
inputFile := args[0]
if inputFile == "-" {
input = os.Stdin
} else {
f, err := os.Open(inputFile)
if err != nil {
return err
}
defer f.Close()
input = f
}

var output io.Writer
if outputFile == "-" {
output = os.Stdout
} else {
f, err := os.Create(outputFile)
if err != nil {
return err
}
defer f.Close()
output = f
}
return decrypt(identities, input, output)
},
}

cmd.Flags().StringArrayP(FlagIdentity, "i", []string{types.DefaultKeyringName}, "identity (can be repeated)")
cmd.Flags().StringP(flags.FlagOutput, "o", "-", "output file (default stdout)")

return cmd
}

func decrypt(identities []age.Identity, in io.Reader, out io.Writer) error {
r, err := age.Decrypt(in, identities...)
if err != nil {
return err
}
if _, err := io.Copy(out, r); err != nil {
return err
}
return nil
}
Loading

0 comments on commit 87efbec

Please sign in to comment.