-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
386 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// package main for keycreator, an example of what a key creator | ||
// can look like | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/neicnordic/crypt4gh/keys" | ||
"golang.org/x/crypto/chacha20poly1305" | ||
) | ||
|
||
// usage prints a nice message to instruct the user | ||
func usage(path string) { | ||
fmt.Printf(`Usage: %s PUBLICKEY PRIVATEKEY PASSWORD | ||
Generate a pair of public and privatekey and write the public key to PUBLICKEY | ||
and the private to PRIVATEKEY. PRIVATEKEY will be encrypted with PASSWORD. | ||
`, path) | ||
os.Exit(0) | ||
|
||
} | ||
|
||
// generateAndWriteKeyFiles does the heavy lifting here, generating | ||
// a keypair and writing them to the specified filenames, the | ||
// private key encrypted with password | ||
func generateAndWriteKeyFiles(publicKeyFileName, privateKeyFileName, password string) (err error) { | ||
publicKey := [chacha20poly1305.KeySize]byte{} | ||
var privateKey [chacha20poly1305.KeySize]byte | ||
|
||
// Get a keypair | ||
publicKey, privateKey, err = keys.GenerateKeyPair() | ||
if err != nil { | ||
return fmt.Errorf("Error while generating key pair: %v", err) | ||
} | ||
|
||
w, err := os.Create(privateKeyFileName) | ||
if err != nil { | ||
return fmt.Errorf("Error when opening private key output %s: %v", privateKeyFileName, err) | ||
} | ||
|
||
// Write the private key as a crypt4gh x25519 key | ||
if err := keys.WriteCrypt4GHX25519PrivateKey(w, privateKey, []byte(password)); err != nil { | ||
return fmt.Errorf("Error when writing private key: %v", err) | ||
} | ||
|
||
if err = w.Close(); err != nil { | ||
return fmt.Errorf("Error when closing private key file: %v", err) | ||
} | ||
|
||
w, err = os.Create(publicKeyFileName) | ||
if err != nil { | ||
return fmt.Errorf("Error when opening public key output %s: %v", publicKeyFileName, err) | ||
} | ||
|
||
if err := keys.WriteCrypt4GHX25519PublicKey(w, publicKey); err != nil { | ||
return fmt.Errorf("Error when closing public key file: %v", err) | ||
} | ||
|
||
if err = w.Close(); err != nil { | ||
return fmt.Errorf("Error when closing private key file: %v", err) | ||
} | ||
|
||
fmt.Printf("Wrote public key to %s and private key to %s\n\n", publicKeyFileName, privateKeyFileName) | ||
|
||
return nil | ||
} | ||
|
||
// main is the function we start in | ||
func main() { | ||
args := os.Args | ||
|
||
if len(args) != 4 { | ||
usage(args[0]) // Won't return | ||
} | ||
|
||
publicKeyFileName := args[1] | ||
privateKeyFileName := args[2] | ||
password := args[3] | ||
|
||
// Use our utility function | ||
err := generateAndWriteKeyFiles(publicKeyFileName, privateKeyFileName, password) | ||
if err != nil { | ||
fmt.Printf("Error during key creation: %v", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
// package main for reader, an example of what a crypt4gh file reader | ||
// can look like | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
|
||
"strconv" | ||
|
||
"github.com/neicnordic/crypt4gh/keys" | ||
"github.com/neicnordic/crypt4gh/streaming" | ||
"golang.org/x/crypto/chacha20poly1305" | ||
) | ||
|
||
// readPublicKey reads the public key from filename and returns the key | ||
// and/or any error encountered. | ||
func readPublicKey(filename string) ([chacha20poly1305.KeySize]byte, error) { | ||
reader, err := os.Open(filename) | ||
|
||
if err != nil { | ||
var nilKey [chacha20poly1305.KeySize]byte | ||
return nilKey, err | ||
} | ||
|
||
key, err := keys.ReadPublicKey(reader) | ||
reader.Close() | ||
return key, err | ||
} | ||
|
||
// readPrivateKey reads the private key file designated by filename | ||
// encrypted with password, if any. | ||
func readPrivateKey(filename string, password []byte) ([chacha20poly1305.KeySize]byte, error) { | ||
reader, err := os.Open(filename) | ||
|
||
if err != nil { | ||
var nilKey [chacha20poly1305.KeySize]byte | ||
return nilKey, err | ||
} | ||
|
||
key, err := keys.ReadPrivateKey(reader, password) | ||
reader.Close() | ||
return key, err | ||
} | ||
|
||
// readFile reads and decrypts | ||
func readFile(filename string, writer io.Writer, readerKey [chacha20poly1305.KeySize]byte, start, end int64) error { | ||
|
||
underReader, err := os.Open(filename) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer underReader.Close() | ||
|
||
reader, err := streaming.NewCrypt4GHReader(underReader, readerKey, nil) | ||
if err != nil { | ||
return err | ||
} | ||
defer reader.Close() | ||
|
||
if start != 0 { | ||
// We don't want to read from start, skip ahead to where we should be | ||
if _, err := reader.Seek(start, 0); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Calculate how much we should read (if given) | ||
togo := end - start | ||
|
||
buf := make([]byte, 4096) | ||
|
||
// Loop until we've read what we should (if no/faulty end given, that's EOF) | ||
for end == 0 || togo > 0 { | ||
rbuf := buf[:] | ||
|
||
if end != 0 && togo < 4096 { | ||
// If we don't want to read as much as 4096 bytes | ||
rbuf = buf[:togo] | ||
} | ||
r, err := reader.Read(rbuf) | ||
togo -= int64(r) | ||
|
||
// Nothing more to read? | ||
if err == io.EOF && r == 0 { | ||
// Fall out without error if we had EOF (if we got any data, do one | ||
// more lap in the loop) | ||
return nil | ||
} | ||
|
||
if err != nil && err != io.EOF { | ||
// An error we want to signal? | ||
return err | ||
} | ||
|
||
wbuf := rbuf[:r] | ||
for len(wbuf) > 0 { | ||
// Loop until we've written all that we could read, | ||
// fall out on error | ||
w, err := writer.Write(wbuf) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
wbuf = wbuf[w:] | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// usage prints a friendly message | ||
func usage(path string) { | ||
fmt.Printf(`Usage: %s INPUT READERPRIVATEKEY PASSWORD [START [END]] | ||
Read and decrypt INPUT (encrypted for the public key corresponding to | ||
READERPRIVATEKEY) and write to stdout. | ||
If start is given, start reading at that offset in the file rather than from | ||
the start. If end is given, stop there (byte at offsent end is not included). | ||
`, path) | ||
os.Exit(0) | ||
} | ||
|
||
// getStartEnd returns the start and end values to use or 0 | ||
// if not provided | ||
func getStartEnd(args []string) (start, end int64, err error) { | ||
if len(args) >= 5 { | ||
start, err = strconv.ParseInt(args[4], 10, 0) | ||
|
||
if err != nil { | ||
return 0, 0, fmt.Errorf("Couldn't parse start offset %s as a decimal number: %v", args[4], err) | ||
} | ||
} | ||
if len(args) == 6 { | ||
end, err = strconv.ParseInt(args[5], 10, 0) | ||
if err != nil { | ||
return 0, 0, fmt.Errorf("Couldn't parse end offset %s as a decimal number: %v", args[5], err) | ||
} | ||
} | ||
|
||
if end != 0 && end <= start { | ||
log.Printf("End specified (%d) but before start (%d), ignoring", end, start) | ||
end = 0 | ||
} | ||
|
||
if end != 0 { | ||
fmt.Printf("Will start at %d and read to the end.\n", start) | ||
return start, end, nil | ||
} | ||
|
||
fmt.Printf("Will start at %d and read to %d.\n", start, end) | ||
return start, end, nil | ||
|
||
} | ||
|
||
// main is where we start | ||
func main() { | ||
args := os.Args | ||
|
||
if len(args) < 4 || len(args) > 6 { | ||
usage(args[0]) // Won't return | ||
} | ||
|
||
inputFilename := args[1] | ||
privateKeyFileName := args[2] | ||
password := args[3] | ||
|
||
// We need the private key to decrypt the file | ||
privateKey, err := readPrivateKey(privateKeyFileName, []byte(password)) | ||
if err != nil { | ||
log.Fatalf("Unexpected error while reading reader key: %v", err) | ||
} | ||
|
||
fmt.Printf("Will read from %s, decrypt and output to stderr.\n", inputFilename) | ||
|
||
// Pick up start and end if passed (will get 0 otherwise) | ||
start, end, err := getStartEnd(args) | ||
if err != nil { | ||
log.Fatalf("Error while parsing start and end: %v", err) | ||
} | ||
|
||
err = readFile(inputFilename, os.Stdout, privateKey, start, end) | ||
if err != nil { | ||
log.Fatalf("Error while decrypting file %s: %v", inputFilename, err) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// package main for writer, an example of what a crypt4gh file writer | ||
// can look like | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
|
||
"github.com/neicnordic/crypt4gh/keys" | ||
"github.com/neicnordic/crypt4gh/streaming" | ||
"golang.org/x/crypto/chacha20poly1305" | ||
) | ||
|
||
// readPublicKey reads the public key from filename and returns the key | ||
// and/or any error encountered. | ||
func readPublicKey(filename string) ([chacha20poly1305.KeySize]byte, error) { | ||
reader, err := os.Open(filename) | ||
|
||
if err != nil { | ||
var nilKey [chacha20poly1305.KeySize]byte | ||
return nilKey, err | ||
} | ||
|
||
key, err := keys.ReadPublicKey(reader) | ||
reader.Close() | ||
return key, err | ||
} | ||
|
||
// readPrivateKey reads the private key from filename, possibly decrypts it | ||
// (if password is supplied) and returns the key and/or any error encountered. | ||
func readPrivateKey(filename string, password []byte) ([chacha20poly1305.KeySize]byte, error) { | ||
reader, err := os.Open(filename) | ||
|
||
if err != nil { | ||
var nilKey [chacha20poly1305.KeySize]byte | ||
return nilKey, err | ||
} | ||
|
||
key, err := keys.ReadPrivateKey(reader, password) | ||
reader.Close() | ||
return key, err | ||
} | ||
|
||
// writeFile reads from the supplied reader and writes to filename | ||
// as a stream encrypted for readerKey, using writerKey | ||
func writeFile(reader io.Reader, writerKey, readerKey [chacha20poly1305.KeySize]byte, filename string) error { | ||
|
||
underWriter, err := os.Create(filename) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer underWriter.Close() | ||
|
||
readerPublicKeyList := [][chacha20poly1305.KeySize]byte{readerKey} | ||
readerPublicKeyList = append(readerPublicKeyList, readerKey) | ||
writer, err := streaming.NewCrypt4GHWriter(underWriter, writerKey, readerPublicKeyList, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if _, err = io.Copy(writer, reader); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func usage(path string) { | ||
fmt.Printf(`Usage: %s OUTPUT READERPUBLICKEY WRITERPRIVATEKEY PASSWORD | ||
Create OUTPUT and wite stdin as a crypt4gh encrypted file, encrypted for | ||
READERPUBLICKEY with WRITERPRIVATEKEY. | ||
`, path) | ||
os.Exit(0) | ||
} | ||
|
||
func main() { | ||
args := os.Args | ||
|
||
if len(args) == 1 { | ||
usage(args[0]) // Won't return | ||
} | ||
|
||
outputFilename := args[1] | ||
publicKeyFileName := args[2] | ||
privateKeyFileName := args[3] | ||
password := args[4] | ||
|
||
var err error | ||
publicKey, err := readPublicKey(publicKeyFileName) | ||
if err != nil { | ||
log.Fatalf("Unexpected error while reading receiver key: %v", err) | ||
} | ||
|
||
privateKey, err := readPrivateKey(privateKeyFileName, []byte(password)) | ||
if err != nil { | ||
log.Fatalf("Unexpected error while reading sender key: %v", err) | ||
} | ||
|
||
fmt.Printf("Will write stdin to %s close when done (e.g. Ctrl-D)\n\n", outputFilename) | ||
err = writeFile(os.Stdin, privateKey, publicKey, outputFilename) | ||
if err != nil { | ||
log.Fatalf("Error from writing encrypted file %s: %v", outputFilename, err) | ||
} | ||
} |