提交 56e9de86 作者: jihao

init

上级 8a05b3ac
The MIT License (MIT)
Copyright (c) 2019 CsterKuroi
Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# ipfs-file-enc # ipfs-file-enc - encrypt file and add to IPFS.
encrypt file and add to IPFS
Currently, IPFS does not have an inbuilt content encryption system. Many solutions exist on top. I wanted something easy. This builds on [senc](https://github.com/jbenet/go-simple-encrypt).
## On the commandline
This tool is command-line based.
### Install
Using go get:
```
go get github.com/Csterkuroi/ipfs-file-enc/ipfs-file-enc
```
### How to encrypt & share
```
# encrypt with a known key. (256bits)
ipfs-file-enc --key <secret-key> share <path-to-file>
# encrypt with a randomly generated key. will be printed out.
ipfs-file-enc share <path-to-file>
```
Leave your IPFS node running, or pin this somewhere.
### How to download & decrypt
```
# will ask for key
ipfs-senc download <ipfs-link> <local-destination-dir>
# decrypt with given key.
ipfs-senc --key <secret-key> download <ipfs-link> [<local-destination-dir>]
```
Will use your local ipfs node, or the ipfs-gateway if no local node is available.
## Example
```
>ipfs-file-enc share index.js
Shared as: /ipfs/Qmanj686x6XgSb685iDmBpenfVFb396ymbEMAegBAp3e7a
Key: zEKiSDNK8vcL5qew7kH2VznEgQaQSU3vJoEnLjXXKkf8j
Ciphertext on global gateway: https://gateway.ipfs.io /ipfs/Qmanj686x6XgSb685iDmBpenfVFb396ymbEMAegBAp3e7a
Ciphertext on local gateway: http://localhost:8080 /ipfs/Qmanj686x6XgSb685iDmBpenfVFb396ymbEMAegBAp3e7a
Get, Decrypt with:
ipfs-file-enc --key zEKiSDNK8vcL5qew7kH2VznEgQaQSU3vJoEnLjXXKkf8j download /ipfs/Qmanj686x6XgSb685iDmBpenfVFb396ymbEMAegBAp3e7a <filename>
>ipfs-file-enc --key zEKiSDNK8vcL5qew7kH2VznEgQaQSU3vJoEnLjXXKkf8j download /ipfs/Qmanj686x6XgSb685iDmBpenfVFb396ymbEMAegBAp3e7a new.js
write to: new.js
```
## TODO or problem
1. cipher in memory
2. need to save file_name, file_mode, key
3. 16 bytes IV
## License
MIT, copyright Csterkuroi.
package main
import (
"errors"
"flag"
"fmt"
"os"
"strings"
ipfsfe "github.com/Csterkuroi/ipfs-file-enc"
senc "github.com/jbenet/go-simple-encrypt"
mb "github.com/multiformats/go-multibase"
)
// flags
var (
Key string
API string
RandomKey bool
)
// errors
var (
ErrNoIPFS = errors.New("ipfs node error: not online")
)
const (
gwayGlobal = "https://gateway.ipfs.io"
gwayLocal = "http://localhost:8080"
)
var Usage = `ENCRYPT AND SEND
# will ask for a key
ipfs-file-enc share <local-file-path>
# encrypt with a known key. (256 bits please)
ipfs-file-enc --key <secret-key> share <local-file-path>
# encrypt with a randomly generated key. will be printed out.
ipfs-file-enc --random-key share <local-file-path>
GET AND DECRYPT
# will ask for key
ipfs-file-enc download <ipfs-link> <local-destination-path>
# decrypt with given key.
ipfs-file-enc --key <secret-key> download <ipfs-link> <local-destination-path>
OPTIONS
--h, --help show usage
--key <secret-key> a 256bit secret key, encoded with multibase (no key = random key)
--api <ipfs-api-url> an ipfs node api to use (overrides defaults)
EXAMPLES
> ipfs-file-enc share my_secret_dir
Enter a 256 bit AES key in multibase:
`
func init() {
flag.BoolVar(&RandomKey, "random-key", false, "use a randomly generated key (deprecated opt)")
flag.StringVar(&Key, "key", "", "an AES encryption key in hex")
flag.StringVar(&API, "api", "", "override IPFS node API")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, Usage)
}
}
func decodeKey(k string) ([]byte, error) {
_, b, err := mb.Decode(k)
if err != nil {
return nil, fmt.Errorf("multibase decoding error: %v", err)
}
if len(b) != 32 {
return nil, fmt.Errorf("key must be exactly 256 bits. Was: %d", len(b))
}
return b, nil
}
func getSencKey(randomIfNone bool) (ipfsfe.Key, error) {
NilKey := ipfsfe.Key(nil)
var k []byte
var err error
if Key != "" {
k, err = decodeKey(Key)
} else if randomIfNone { // random key
k, err = senc.RandomKey()
} else {
err = errors.New("Please enter a key with --key")
}
if err != nil {
return NilKey, err
}
return ipfsfe.Key(k), nil
}
func cmdDownload(args []string) error {
if RandomKey {
return errors.New("cannot use --random-key with download")
}
if len(args) < 2 {
return errors.New("not enough arguments. download requires 2. see -h")
}
srcLink := ipfsfe.IPFSLink(args[0])
if len(srcLink) < 1 {
return errors.New("invalid ipfs-link")
}
dstPath := args[1]
if dstPath == "" {
return errors.New("requires a destination path")
}
// check for Key, get key.
key, err := getSencKey(false)
if err != nil {
return err
}
// fmt.Println("Initializing ipfs node...")
n := ipfsfe.GetROIPFSNode(API)
if !n.IsUp() {
return ErrNoIPFS
}
// fmt.Println("Getting", srcLink, "...")
err = ipfsfe.GetDecrypt(n, srcLink, dstPath, key)
if err != nil {
return err
}
fmt.Println("write to:", dstPath)
return nil
}
func cmdShare(args []string) error {
if len(args) < 1 {
return errors.New("not enough arguments. share requires 1. see -h")
}
srcPath := args[0]
if srcPath == "" {
return errors.New("requires a source path")
}
// check for Key, get key.
key, err := getSencKey(true)
if err != nil {
return err
}
// fmt.Println("Initializing ipfs node...")
n, err := ipfsfe.GetRWIPFSNode(API)
if err != nil {
return err
}
if !n.IsUp() {
return ErrNoIPFS
}
// fmt.Println("Sharing", srcPath, "...")
link, err := ipfsfe.EncryptAndPut(n, srcPath, key)
if err != nil {
return err
}
l := string(link)
if !strings.HasPrefix(l, "/ipfs/") {
l = "/ipfs/" + l
}
keyStr, err := mb.Encode(mb.Base58BTC, key)
if err != nil {
return err
}
fmt.Println("Shared as: ", l)
fmt.Println("Key: ", keyStr)
fmt.Println("Ciphertext on global gateway: ", gwayGlobal, l)
fmt.Println("Ciphertext on local gateway: ", gwayLocal, l)
fmt.Println("")
fmt.Println("Get, Decrypt with:")
fmt.Println(" ipfs-file-enc --key", keyStr, "download", l, "<filename>")
fmt.Println("")
return nil
}
func errMain(args []string) error {
// no command is not an error. it's usage.
if len(args) == 0 {
fmt.Println(Usage)
return nil
}
cmd := args[0]
switch cmd {
case "download":
return cmdDownload(args[1:])
case "share":
return cmdShare(args[1:])
default:
return errors.New("Unknown command: " + cmd)
}
}
func main() {
flag.Parse()
args := flag.Args()
if err := errMain(args); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(-1)
}
}
package ipfssenc
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
ipfs "github.com/ipfs/go-ipfs-api"
senc "github.com/jbenet/go-simple-encrypt"
)
type IPFSLink string
type Key []byte
var (
ErrNotImplemented = errors.New("ErrNotImplemented")
ErrFailedToUseLocalNode = errors.New("Failed to use local node")
)
var (
GlobalNodeURL = "https://gateway.ipfs.io:4001"
GlobalGatewayURL = "https://gateway.ipfs.io"
LocalNodeURL = "http://localhost:4001"
LocalGatewayURL = "http://localhost:8080"
)
func GetRWIPFSNode(url string) (*ipfs.Shell, error) {
// must be a local node.
if url != "" {
return ipfs.NewShell(url), nil
}
// no url given. try local
if n := ipfs.NewLocalShell(); n != nil {
return n, nil
}
// try LocalGatewayURL
if n := ipfs.NewShell(LocalNodeURL); n != nil {
return n, nil
}
return nil, ErrFailedToUseLocalNode
}
func GetROIPFSNode(url string) *ipfs.Shell {
rwn, err := GetRWIPFSNode(url)
if err == nil {
return rwn
}
// use global gateway.
return ipfs.NewShell(GlobalNodeURL)
}
// Encrypt encrypts a given PlainText w/ given Key.
func Encrypt(pt io.Reader, secret Key) (ct io.Reader, err error) {
return senc.Encrypt(secret, pt)
}
// Decrypt decrypts a given CipherText w/ given Key.
func Decrypt(ct io.Reader, secret Key) (pt io.Reader, err error) {
return senc.Decrypt(secret, ct)
}
// Put adds a given Reader to the network, and gets a link for it.
func Put(n *ipfs.Shell, r io.Reader) (IPFSLink, error) {
s, err := n.Add(r)
if s != "" {
s = "/ipfs/" + s
}
return IPFSLink(s), err
}
// Get retrieves a CipherText for given Link from the network.
func Get(n *ipfs.Shell, link IPFSLink) (io.ReadCloser, error) {
return n.Cat(string(link))
}
func EncryptAndPut(n *ipfs.Shell, localPath string, secret Key) (IPFSLink, error) {
if _, err := os.Stat(localPath); err != nil {
return IPFSLink(""), fmt.Errorf("Unable to open files - %v", err.Error())
}
srcIsDir := false
if fi, err := os.Stat(localPath); err != nil {
return IPFSLink("") ,err
} else {
srcIsDir = fi.IsDir()
}
if srcIsDir{
return IPFSLink("") ,fmt.Errorf("Unable to open dir")
}
f, err := os.Open(localPath)
defer f.Close()
c, err := Encrypt(f, secret)
if err != nil {
return IPFSLink(""), err
}
return Put(n, c)
}
func GetDecrypt(n *ipfs.Shell, link IPFSLink, localPath string, secret Key) error {
ct, err := Get(n, link)
if err != nil {
return err
}
defer func() {
// ipfs-api.Cat docs say to drain the reader and close it.
io.Copy(ioutil.Discard, ct)
ct.Close()
}()
pt, err := Decrypt(ct, secret)
if err != nil {
return err
}
f, err := os.OpenFile(localPath, os.O_CREATE|os.O_RDWR, os.FileMode(0644))
// copy over contents
if _, err := io.Copy(f, pt); err != nil {
return err
}
return nil
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论