From 0f38879de78ca62158dedafb22af9a6186067438 Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Sun, 26 Jul 2020 17:27:38 -0700
Subject: [PATCH 1/4] saltpack: Autodetect decrypt/verify input
---
edx25519.go | 2 +-
errors.go | 3 +
saltpack/README.md | 171 +----------------
saltpack/detect.go | 61 ++++++
saltpack/detect_test.go | 48 +++++
saltpack/encrypt.go | 168 ++++++++++-------
saltpack/encrypt_examples_test.go | 14 +-
saltpack/encrypt_test.go | 100 +++++++---
saltpack/saltpack.go | 26 ++-
saltpack/sign.go | 296 +++++++++++++++++++++---------
saltpack/sign_examples_test.go | 10 +-
saltpack/sign_test.go | 105 +++++++++--
saltpack/signcrypt.go | 91 ++++-----
saltpack/signcrypt_test.go | 67 ++++---
14 files changed, 706 insertions(+), 456 deletions(-)
create mode 100644 saltpack/detect.go
create mode 100644 saltpack/detect_test.go
diff --git a/edx25519.go b/edx25519.go
index c61dd47..5abb784 100644
--- a/edx25519.go
+++ b/edx25519.go
@@ -228,7 +228,7 @@ func (s *EdX25519PublicKey) Verify(b []byte) ([]byte, error) {
}
_, ok := sign.Open(nil, b, s.publicKey)
if !ok {
- return nil, errors.Errorf("verify failed")
+ return nil, ErrVerifyFailed
}
return b[sign.Overhead:], nil
}
diff --git a/errors.go b/errors.go
index 2a7442a..0780b3b 100644
--- a/errors.go
+++ b/errors.go
@@ -6,6 +6,9 @@ import (
"github.com/pkg/errors"
)
+// ErrVerifyFailed if key verify failed.
+var ErrVerifyFailed = errors.New("verify failed")
+
// ErrNotFound describes a key not found error when a key is required.
type ErrNotFound struct {
ID string
diff --git a/saltpack/README.md b/saltpack/README.md
index e2abb2c..304b493 100644
--- a/saltpack/README.md
+++ b/saltpack/README.md
@@ -1,171 +1,10 @@
# Saltpack
-This package allows you to encrypt/decrypt and sign/verify using Saltpack and
-EdX25519 keys.
+See [saltpack.org](https://saltpack.org) for more details.
-For more details visit **[keys.pub](https://keys.pub)**.
+This [github.com/keys-pub/keys/saltpack](https://github.com/keys-pub/keys/tree/master/saltpack) package allows you to encrypt/decrypt, sign/verify using Saltpack.
-## Encrypt
+## Examples
-The following example describes how to:
-
-- Generate an EdX25519 key
-- Encrypt to recipients (Alice and Bob) using Saltpack
-
-```go
-import (
- "github.com/keys-pub/keys"
- "github.com/keys-pub/keys/saltpack"
-)
-
-...
-// Alice
-alice := keys.GenerateEdX25519Key()
-
-// Bob
-bobID := keys.ID("kex1yy7amjzd5ld3k0uphvyetlz2vd8yy3fky64dut9jdf9qh852f0nsxjgv0m")
-
-message := []byte("hi bob")
-
-// Encrypt using Saltpack from alice to bob (include alice as a recipient too).
-sp := saltpack.New(nil)
-encrypted, err := sp.EncryptArmored(message, alice.X25519Key(), bobID, alice.ID())
-if err != nil {
- log.Fatal(err)
-}
-
-fmt.Printf("Encrypted: %s\n", string(encrypted))
-```
-
-## Decrypt
-
-The following example decrypts the message from the Encrypt example:
-
-- Initialize and setup/unlock a Keyring
-- Create a Store
-- Import a EdX25519 key
-- Decrypt and verify a Saltpack message
-
-```go
-import (
- "github.com/keys-pub/keys"
- "github.com/keys-pub/keys/keyring"
- "github.com/keys-pub/keys/saltpack"
-)
-
-...
-
-// Message from Alice
-aliceID := keys.ID("kex1vrpxw9rqmf49kygc7ujjrdlx8lkzaarjc3s24j73xlqxhwvsyx2sw06r82")
-encrypted := `BEGIN SALTPACK ENCRYPTED MESSAGE.
-kcJn5brvybfNjz6 D5ll2Nk0YusOJBf 9x1CB6V3o7cdMOV ZPenXvEVhLpMBj0 8rJiM2GJTyXbhDn
-cGIoczvWtRoxL5r 3EIPrfVqpwhLDke LfCV6YykdYdGwY1 lUfrzkOIUGdeURb HDSwgrTSrcexwj3
-ix9Mw1FVXQGBwBV yil8lLyD1q0VFGv KmgJYyARppqQEIF HgAsZq0BJL6Dosz WGrFalmG90QA6PO
-avDlwRXMDbjKFvE wQtaBDKXVSBaM9k 0Xu0CfdGUkEICbN vZNV67cGqEz2IiH kr8.
-END SALTPACK ENCRYPTED MESSAGE.`
-
-// Bob creates a Keyring and Store
-kr, err := keyring.New("BobKeyring")
-if err != nil {
- log.Fatal(err)
-}
-if err := kr.UnlockWithPassword("bobpassword", true); err != nil {
- log.Fatal(err)
-}
-ks := keys.NewStore(kr)
-
-// Import edx25519 key to bob's Store
-kmsg := `BEGIN EDX25519 KEY MESSAGE.
-E9zL57KzBY1CIdJ d5tlpnyCIX8R5DB oLswy2g17kbfK4s CwryRUoII3ZNk3l
-scLQrPmgNuKi9OK 7ugGoVWBY2n5xbK 7w500Vp2iXo6LAe XZiB06UjUdCoYJv
-YjKbul2B61uxTZc waeBgRV91RZoKCn xLQnRhLXE2KC.
-END EDX25519 KEY MESSAGE.`
-bob, err := keys.DecodeKeyFromSaltpack(kmsg, "password", false)
-if err != nil {
- log.Fatal(err)
-}
-if err := ks.SaveKey(bob); err != nil {
- log.Fatal(err)
-}
-
-// Bob decrypts the saltpack message.
-sp := saltpack.New(ks)
-out, sender, err := sp.DecryptArmored(encrypted)
-if err != nil {
- log.Fatal(err)
-}
-
-// The sender from Saltpack Decrypt is a X25519 public key, so find the
-// corresponding EdX25519 public key.
-if sender != nil {
- pk, err := ks.FindEdX25519PublicKey(sender.ID())
- if err != nil {
- log.Fatal(err)
- }
- if pk != nil && pk.ID() == aliceID {
- fmt.Printf("signer is alice\n")
- }
-}
-
-fmt.Printf("%s\n", string(out))
-```
-
-## Sign
-
-Sign bytes to an armored saltpack message.
-
-```go
-import (
- "github.com/keys-pub/keys"
- "github.com/keys-pub/keys/saltpack"
-)
-...
-
-sp := saltpack.New(nil)
-
-alice := keys.GenerateEdX25519Key()
-
-message := []byte("hi from alice")
-
-sig, err := sp.SignArmored(message, alice)
-if err != nil {
- log.Fatal(err)
-}
-fmt.Printf("%s\n", alice.ID())
-fmt.Printf("%s\n", sig)
-```
-
-## Verify
-
-Verify a signed saltpack message.
-
-```go
-import (
- "github.com/keys-pub/keys"
- "github.com/keys-pub/keys/saltpack"
-)
-...
-
-sp := saltpack.New(nil)
-
-aliceID := keys.ID("kex1w2jep8dkr2s0g9kx5g6xe3387jslnlj08yactvn8xdtrx4cnypjq9rpnux")
-signed := `BEGIN SALTPACK SIGNED MESSAGE.
-kXR7VktZdyH7rvq v5wcIkHbs7mPCSd NhKLR9E0K47y29T QkuYinHym6EfZwL
-1TwgxI3RQ52fHg5 1FzmLOMghcYLcV7 i0l0ovabGhxGrEl z7WuI4O3xMU5saq
-U28RqUnKNroATPO 5rn2YyQcut2SeMn lXJBlDqRv9WyxjG M0PcKvsAsvmid1m
-cqA4TCjz5V9VpuO zuIQ55lRQLeP5kU aWFxq5Nl8WsPqlR RdX86OuTbaKUvKI
-wdNd6ISacrT0I82 qZ71sc7sTxiMxoI P43uCGaAZZ3Ab62 vR8N6WQPE8.
-END SALTPACK SIGNED MESSAGE.`
-
-out, signer, err := sp.VerifyArmored(signed)
-if err != nil {
- log.Fatal(err)
-}
-if signer == aliceID {
- fmt.Printf("signer is alice\n")
-}
-fmt.Printf("%s\n", string(out))
-// Output:
-// signer is alice
-// hi from alice
-```
+- [Encrypt + Decrypt](https://github.com/keys-pub/keys/blob/master/saltpack/encrypt_examples_test.go)
+- [Sign + Verify](https://github.com/keys-pub/keys/blob/master/saltpack/sign_examples_test.go)
diff --git a/saltpack/detect.go b/saltpack/detect.go
new file mode 100644
index 0000000..035e015
--- /dev/null
+++ b/saltpack/detect.go
@@ -0,0 +1,61 @@
+package saltpack
+
+import (
+ "bytes"
+
+ ksaltpack "github.com/keybase/saltpack"
+ "github.com/keys-pub/keys"
+)
+
+// Encoding for saltpack (armored vs binary, encrypt vs signcrypt).
+type Encoding string
+
+const (
+ // UnknownEncoding is unknown.
+ UnknownEncoding Encoding = ""
+ // EncryptEncoding used saltpack.Encrypt
+ EncryptEncoding Encoding = "encrypt"
+ // SigncryptEncoding used saltpack.Signcrypt
+ SigncryptEncoding Encoding = "signcrypt"
+ // SignEncoding used saltpack.Sign
+ SignEncoding Encoding = "sign"
+)
+
+func detectEncrypt(b []byte) (Encoding, bool) {
+ if _, _, err := NewDecryptStream(bytes.NewReader(b), false, nil); err == ksaltpack.ErrNoDecryptionKey {
+ return EncryptEncoding, false
+ }
+ if _, _, err := NewDecryptStream(bytes.NewReader(b), true, nil); err == ksaltpack.ErrNoDecryptionKey {
+ return EncryptEncoding, true
+ }
+ if _, _, err := NewSigncryptOpenStream(bytes.NewReader(b), false, nil); err == ksaltpack.ErrNoDecryptionKey {
+ return SigncryptEncoding, false
+ }
+ if _, _, err := NewSigncryptOpenStream(bytes.NewReader(b), true, nil); err == ksaltpack.ErrNoDecryptionKey {
+ return SigncryptEncoding, true
+ }
+ return UnknownEncoding, false
+}
+
+func detectSign(b []byte) (Encoding, bool) {
+ kr := &saltpack{}
+ if _, _, _, err := ksaltpack.NewDearmor62VerifyStream(signVersionValidator, bytes.NewReader(b), kr); err == nil {
+ return SignEncoding, true
+ }
+ if _, _, err := ksaltpack.NewVerifyStream(signVersionValidator, bytes.NewReader(b), kr); err == nil {
+ return SignEncoding, false
+ }
+ return UnknownEncoding, false
+}
+
+func detectSignDetached(b []byte) (Encoding, bool) {
+ kr := &saltpack{}
+ var buf bytes.Buffer
+ if _, _, err := ksaltpack.Dearmor62VerifyDetachedReader(signVersionValidator, &buf, string(b), kr); err == keys.ErrVerifyFailed {
+ return SignEncoding, true
+ }
+ if _, err := ksaltpack.VerifyDetachedReader(signVersionValidator, &buf, b, kr); err == keys.ErrVerifyFailed {
+ return SignEncoding, false
+ }
+ return UnknownEncoding, false
+}
diff --git a/saltpack/detect_test.go b/saltpack/detect_test.go
new file mode 100644
index 0000000..228cb3d
--- /dev/null
+++ b/saltpack/detect_test.go
@@ -0,0 +1,48 @@
+package saltpack
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/keys-pub/keys"
+ "github.com/stretchr/testify/require"
+)
+
+func TestDetectEncrypt(t *testing.T) {
+ alice := keys.NewEdX25519KeyFromSeed(testSeed(0x01))
+ bob := keys.NewEdX25519KeyFromSeed(testSeed(0x02))
+ message := []byte("hi bob")
+ xalice := alice.X25519Key()
+ xbob := bob.X25519Key()
+
+ encrypted, err := Encrypt(message, false, xalice, xbob.ID())
+ require.NoError(t, err)
+ enc, armored := detectEncrypt(encrypted)
+ require.Equal(t, EncryptEncoding, enc)
+ require.False(t, armored)
+
+ out, err := Encrypt(message, true, xalice, xbob.ID())
+ require.NoError(t, err)
+ enc, armored = detectEncrypt([]byte(out))
+ require.Equal(t, EncryptEncoding, enc)
+ require.True(t, armored)
+
+ signcrypted, err := Signcrypt(message, false, alice, bob.ID())
+ require.NoError(t, err)
+ enc, armored = detectEncrypt([]byte(signcrypted))
+ require.Equal(t, SigncryptEncoding, enc)
+ require.True(t, armored)
+
+ out, err = Signcrypt(message, true, alice, bob.ID())
+ require.NoError(t, err)
+ enc, armored = detectEncrypt([]byte(out))
+ require.Equal(t, SigncryptEncoding, enc)
+ require.True(t, armored)
+
+ enc, _ = detectEncrypt([]byte{0x01})
+ require.Equal(t, UnknownEncoding, enc)
+}
+
+func testSeed(b byte) *[32]byte {
+ return keys.Bytes32(bytes.Repeat([]byte{b}, 32))
+}
diff --git a/saltpack/encrypt.go b/saltpack/encrypt.go
index f001977..0f9181a 100644
--- a/saltpack/encrypt.go
+++ b/saltpack/encrypt.go
@@ -1,7 +1,9 @@
package saltpack
import (
+ "bufio"
"io"
+ "reflect"
"github.com/keys-pub/keys"
"github.com/pkg/errors"
@@ -12,7 +14,7 @@ import (
// Encrypt to recipients.
// Sender can be nil, if you want it to be anonymous.
// https://saltpack.org/encryption-format-v2
-func Encrypt(b []byte, sender *keys.X25519Key, recipients ...keys.ID) ([]byte, error) {
+func Encrypt(b []byte, armored bool, sender *keys.X25519Key, recipients ...keys.ID) ([]byte, error) {
recs, err := boxPublicKeys(recipients)
if err != nil {
return nil, err
@@ -21,22 +23,14 @@ func Encrypt(b []byte, sender *keys.X25519Key, recipients ...keys.ID) ([]byte, e
if sender != nil {
sbk = newBoxKey(sender)
}
- return ksaltpack.Seal(ksaltpack.Version2(), b, sbk, recs)
-}
-
-// EncryptArmored to recipients.
-// Sender can be nil, if you want it to be anonymous.
-// https://saltpack.org/encryption-format-v2
-func EncryptArmored(b []byte, sender *keys.X25519Key, recipients ...keys.ID) (string, error) {
- recs, err := boxPublicKeys(recipients)
- if err != nil {
- return "", err
- }
- var sbk ksaltpack.BoxSecretKey
- if sender != nil {
- sbk = newBoxKey(sender)
+ if armored {
+ s, err := ksaltpack.EncryptArmor62Seal(ksaltpack.Version2(), b, sbk, recs, "")
+ if err != nil {
+ return nil, err
+ }
+ return []byte(s), nil
}
- return ksaltpack.EncryptArmor62Seal(ksaltpack.Version2(), b, sbk, recs, "")
+ return ksaltpack.Seal(ksaltpack.Version2(), b, sbk, recs)
}
func x25519SenderKey(info *ksaltpack.MessageKeyInfo) (*keys.X25519PublicKey, error) {
@@ -44,34 +38,42 @@ func x25519SenderKey(info *ksaltpack.MessageKeyInfo) (*keys.X25519PublicKey, err
if !info.SenderIsAnon {
b := info.SenderKey.ToKID()
if len(b) != 32 {
- return nil, errors.Errorf("invalid (x25519) sender key")
+ return nil, errors.Errorf("invalid x25519 sender key")
}
sender = keys.NewX25519PublicKey(keys.Bytes32(b))
}
return sender, nil
}
-// Decrypt bytes (using the specified keys).
-// If there was a sender, will return a X25519 key ID.
-func Decrypt(b []byte, ks KeyStore) ([]byte, *keys.X25519PublicKey, error) {
- s := newSaltpack(ks)
- info, out, err := ksaltpack.Open(encryptVersionValidator, b, s)
- if err != nil {
- return nil, nil, convertBoxKeyErr(err)
- }
- sender, err := x25519SenderKey(info)
- if err != nil {
- return nil, nil, err
- }
- return out, sender, nil
+// Open decrypts bytes after attempting to auto detect the encoding.
+func Open(b []byte, kr Keyring) (out []byte, key keys.Key, enc Encoding, err error) {
+ enc, armored := detectEncrypt(b)
+ switch enc {
+ case EncryptEncoding:
+ out, key, err = Decrypt(b, armored, kr)
+ case SigncryptEncoding:
+ out, key, err = SigncryptOpen(b, armored, kr)
+ default:
+ err = errors.Errorf("invalid data")
+ }
+ if isNil(key) {
+ key = nil
+ }
+ return
}
-// DecryptArmored text (using the specified keys).
-// If there was a sender, will return a X25519 key ID.
-func DecryptArmored(str string, ks KeyStore) ([]byte, *keys.X25519PublicKey, error) {
- s := newSaltpack(ks)
- // TODO: Casting to string could be a performance issue
- info, out, _, err := ksaltpack.Dearmor62DecryptOpen(encryptVersionValidator, str, s)
+// Decrypt bytes.
+// If there was a sender, will return the X25519 public key.
+func Decrypt(b []byte, armored bool, kr Keyring) ([]byte, *keys.X25519PublicKey, error) {
+ s := newSaltpack(kr)
+ var info *ksaltpack.MessageKeyInfo
+ var out []byte
+ var err error
+ if armored {
+ info, out, _, err = ksaltpack.Dearmor62DecryptOpen(encryptVersionValidator, string(b), s)
+ } else {
+ info, out, err = ksaltpack.Open(encryptVersionValidator, b, s)
+ }
if err != nil {
return nil, nil, convertBoxKeyErr(err)
}
@@ -82,9 +84,9 @@ func DecryptArmored(str string, ks KeyStore) ([]byte, *keys.X25519PublicKey, err
return out, sender, nil
}
-// NewEncryptStream creates an encrypted io.WriteCloser.
+// NewEncryptStream creates an encrypted armored io.WriteCloser.
// Sender can be nil, if you want it to be anonymous.
-func NewEncryptStream(w io.Writer, sender *keys.X25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
+func NewEncryptStream(w io.Writer, armored bool, sender *keys.X25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
recs, err := boxPublicKeys(recipients)
if err != nil {
return nil, err
@@ -93,28 +95,51 @@ func NewEncryptStream(w io.Writer, sender *keys.X25519Key, recipients ...keys.ID
if sender != nil {
sbk = newBoxKey(sender)
}
+ if armored {
+ return ksaltpack.NewEncryptArmor62Stream(ksaltpack.Version2(), w, sbk, recs, "")
+ }
return ksaltpack.NewEncryptStream(ksaltpack.Version2(), w, sbk, recs)
}
-// NewEncryptArmoredStream creates an encrypted armored io.WriteCloser.
-// Sender can be nil, if you want it to be anonymous.
-func NewEncryptArmoredStream(w io.Writer, sender *keys.X25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
- recs, err := boxPublicKeys(recipients)
+// NewReader creates io.Reader for decryption after trying to detect the encoding.
+// We peek up to 512 bytes from the reader, detect the encoding and return that stream.
+func NewReader(r io.Reader, kr Keyring) (out io.Reader, key keys.Key, enc Encoding, err error) {
+ buf := bufio.NewReader(r)
+ var peek []byte
+ peek, err = buf.Peek(512)
if err != nil {
- return nil, err
+ if err != io.EOF {
+ return
+ }
}
- var sbk ksaltpack.BoxSecretKey
- if sender != nil {
- sbk = newBoxKey(sender)
+ enc, armored := detectEncrypt(peek)
+ switch enc {
+ case EncryptEncoding:
+ out, key, err = NewDecryptStream(buf, armored, kr)
+ case SigncryptEncoding:
+ out, key, err = NewSigncryptOpenStream(buf, armored, kr)
+ default:
+ err = errors.Errorf("invalid data")
}
- return ksaltpack.NewEncryptArmor62Stream(ksaltpack.Version2(), w, sbk, recs, "")
+ if isNil(key) {
+ key = nil
+ }
+ return
}
-// NewDecryptStream creates a decryption stream (using the specified keys).
+// NewDecryptStream creates a decrypt stream.
// If there was a sender, will return a X25519 key ID.
-func NewDecryptStream(r io.Reader, ks KeyStore) (io.Reader, *keys.X25519PublicKey, error) {
- s := newSaltpack(ks)
- info, stream, err := ksaltpack.NewDecryptStream(encryptVersionValidator, r, s)
+func NewDecryptStream(r io.Reader, armored bool, kr Keyring) (io.Reader, *keys.X25519PublicKey, error) {
+ s := newSaltpack(kr)
+
+ var info *ksaltpack.MessageKeyInfo
+ var stream io.Reader
+ var err error
+ if armored {
+ info, stream, _, err = ksaltpack.NewDearmor62DecryptStream(encryptVersionValidator, r, s)
+ } else {
+ info, stream, err = ksaltpack.NewDecryptStream(encryptVersionValidator, r, s)
+ }
if err != nil {
return nil, nil, convertBoxKeyErr(err)
}
@@ -125,18 +150,35 @@ func NewDecryptStream(r io.Reader, ks KeyStore) (io.Reader, *keys.X25519PublicKe
return stream, sender, nil
}
-// NewDecryptArmoredStream creates a decryption stream (using the specified keys).
-// If there was a sender, will return a X25519 key ID.
-func NewDecryptArmoredStream(r io.Reader, ks KeyStore) (io.Reader, *keys.X25519PublicKey, error) {
- s := newSaltpack(ks)
- // TODO: Specifying nil for resolver will panic if box keys not found
- info, stream, _, err := ksaltpack.NewDearmor62DecryptStream(encryptVersionValidator, r, s)
- if err != nil {
- return nil, nil, convertBoxKeyErr(err)
+// isNil checks if a specified object is nil.
+func isNil(object interface{}) bool {
+ if object == nil {
+ return true
}
- sender, err := x25519SenderKey(info)
- if err != nil {
- return nil, nil, err
+
+ value := reflect.ValueOf(object)
+ kind := value.Kind()
+ isNilableKind := containsKind(
+ []reflect.Kind{
+ reflect.Chan, reflect.Func,
+ reflect.Interface, reflect.Map,
+ reflect.Ptr, reflect.Slice},
+ kind)
+
+ if isNilableKind && value.IsNil() {
+ return true
}
- return stream, sender, nil
+
+ return false
+}
+
+// containsKind checks if a specified kind in the slice of kinds.
+func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
+ for i := 0; i < len(kinds); i++ {
+ if kind == kinds[i] {
+ return true
+ }
+ }
+
+ return false
}
diff --git a/saltpack/encrypt_examples_test.go b/saltpack/encrypt_examples_test.go
index 4daa80f..a3f6b88 100644
--- a/saltpack/encrypt_examples_test.go
+++ b/saltpack/encrypt_examples_test.go
@@ -8,14 +8,14 @@ import (
"github.com/keys-pub/keys/saltpack"
)
-func ExampleEncryptArmored() {
+func ExampleEncrypt() {
alice := keys.GenerateX25519Key()
bob := keys.GenerateX25519Key()
message := []byte("hi bob")
// Encrypt from alice to bob
- encrypted, err := saltpack.EncryptArmored(message, alice, bob.ID())
+ encrypted, err := saltpack.Encrypt(message, true, alice, bob.ID())
if err != nil {
log.Fatal(err)
}
@@ -23,16 +23,16 @@ func ExampleEncryptArmored() {
// Output: 375
}
-func ExampleDecryptArmored() {
- // Message from ExampleEncryptArmored
+func ExampleDecrypt() {
+ // Message from ExampleEncrypt
aliceID := keys.ID("kbx17jhqvdrgdyruyseuaat0rerj7ep4n63n4klufzxtzmk9p3d944gs4fg39g")
- encrypted := `BEGIN SALTPACK ENCRYPTED MESSAGE.
+ encrypted := []byte(`BEGIN SALTPACK ENCRYPTED MESSAGE.
kcJn5brvybfNjz6 D5ll2Nk0YiiGFCz I2xgcLXuPzYNBe3 OboFDA8Gh0TxosH yo82IRf2OZzteqO
GaPWlm7t0lC0M0U vNnOvsussLf1nMw Oo1Llf9oAbA7qxa GjupUEWnTgyjjUn GKb3WvtjSgRsJS2
Y92GMEx8cHvbGrJ zvLGlbqAhEIDNZ2 SE15aoV6ahVxeVH 1inHyghv3H1oTAC K86mBl4fg9FY1QK
4n0gLOmSHbD8UYH V3HAPS0yaBC4xJB g3y04Xcqiij36Nb WmJgvSFdGugXd7O yfU.
END SALTPACK ENCRYPTED MESSAGE.
- `
+ `)
// Bob is keys.ID("kbx18x22l7nemmxcj76f9l3aaflc5487lp5u5q778gpe3t3wzhlqvu8qxa9z07")
key := `BEGIN X25519 KEY MESSAGE.
@@ -45,7 +45,7 @@ func ExampleDecryptArmored() {
}
// Bob decrypts
- out, sender, err := saltpack.DecryptArmored(encrypted, saltpack.NewKeyStore(bob))
+ out, sender, err := saltpack.Decrypt(encrypted, true, saltpack.NewKeyring(bob))
if err != nil {
log.Fatal(err)
}
diff --git a/saltpack/encrypt_test.go b/saltpack/encrypt_test.go
index eb983a9..d3649e2 100644
--- a/saltpack/encrypt_test.go
+++ b/saltpack/encrypt_test.go
@@ -16,19 +16,19 @@ func TestEncrypt(t *testing.T) {
message := []byte("hi bob")
- encrypted, err := saltpack.Encrypt(message, alice, bob.ID())
+ encrypted, err := saltpack.Encrypt(message, false, alice, bob.ID())
require.NoError(t, err)
- out, sender, err := saltpack.Decrypt(encrypted, saltpack.NewKeyStore(bob))
+ out, sender, err := saltpack.Decrypt(encrypted, false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- encrypted2, err := saltpack.EncryptArmored(message, alice, bob.ID())
+ encrypted2, err := saltpack.Encrypt(message, true, alice, bob.ID())
require.NoError(t, err)
- out, sender, err = saltpack.DecryptArmored(encrypted2, saltpack.NewKeyStore(bob))
+ out, sender, err = saltpack.Decrypt([]byte(encrypted2), true, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.NotNil(t, sender)
@@ -43,11 +43,11 @@ func TestEncrypt(t *testing.T) {
// require.NotNil(t, sender)
// require.Equal(t, alice.PublicKey().ID(), sender.ID())
- _, err = saltpack.Encrypt(message, alice, keys.ID(""))
+ _, err = saltpack.Encrypt(message, false, alice, keys.ID(""))
require.EqualError(t, err, "invalid recipient: empty id")
// Duplicate recipient
- _, err = saltpack.Encrypt(message, alice, bob.ID(), bob.ID())
+ _, err = saltpack.Encrypt(message, false, alice, bob.ID(), bob.ID())
require.NoError(t, err)
}
@@ -55,48 +55,80 @@ func TestEncryptAnon(t *testing.T) {
bob := keys.NewX25519KeyFromSeed(testSeed(0x02))
message := []byte("hi bob")
// Anon sender
- encrypted, err := saltpack.Encrypt(message, nil, bob.ID())
+ encrypted, err := saltpack.Encrypt(message, false, nil, bob.ID())
require.NoError(t, err)
- out, sender, err := saltpack.Decrypt(encrypted, saltpack.NewKeyStore(bob))
+ out, sender, err := saltpack.Decrypt(encrypted, false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.Nil(t, sender)
}
+func copyBytes(source []byte) []byte {
+ dest := make([]byte, len(source))
+ copy(dest, source)
+ return dest
+}
+
func TestEncryptStream(t *testing.T) {
alice := keys.GenerateX25519Key()
bob := keys.GenerateX25519Key()
message := []byte("hi bob")
var buf bytes.Buffer
- encrypted, err := saltpack.NewEncryptStream(&buf, alice, bob.ID())
+ stream, err := saltpack.NewEncryptStream(&buf, false, alice, bob.ID())
require.NoError(t, err)
- n, err := encrypted.Write(message)
+ n, err := stream.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
- encrypted.Close()
+ stream.Close()
+ encrypted := copyBytes(buf.Bytes())
- stream, sender, err := saltpack.NewDecryptStream(&buf, saltpack.NewKeyStore(bob))
+ dstream, sender, err := saltpack.NewDecryptStream(bytes.NewReader(encrypted), false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- out, err := ioutil.ReadAll(stream)
+ out, err := ioutil.ReadAll(dstream)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+
+ dstream, key, enc, err := saltpack.NewReader(bytes.NewReader(encrypted), saltpack.NewKeyring(bob))
+ require.NoError(t, err)
+ require.NotNil(t, key)
+ require.Equal(t, saltpack.EncryptEncoding, enc)
+ require.Equal(t, alice.PublicKey().ID(), key.ID())
+ out, err = ioutil.ReadAll(dstream)
require.NoError(t, err)
require.Equal(t, message, out)
+}
+
+func TestEncryptArmoredStream(t *testing.T) {
+ alice := keys.GenerateX25519Key()
+ bob := keys.GenerateX25519Key()
+ message := []byte("hi bob")
- var buf2 bytes.Buffer
- encrypted2, err := saltpack.NewEncryptArmoredStream(&buf2, alice, bob.ID())
+ var buf bytes.Buffer
+ stream, err := saltpack.NewEncryptStream(&buf, true, alice, bob.ID())
require.NoError(t, err)
- n, err = encrypted2.Write(message)
+ n, err := stream.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
- encrypted2.Close()
+ stream.Close()
+ encrypted := copyBytes(buf.Bytes())
- stream, sender, err = saltpack.NewDecryptArmoredStream(&buf2, saltpack.NewKeyStore(bob))
+ dstream, sender, err := saltpack.NewDecryptStream(bytes.NewReader(encrypted), true, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- out, err = ioutil.ReadAll(stream)
+ out, err := ioutil.ReadAll(dstream)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+
+ dstream, key, enc, err := saltpack.NewReader(bytes.NewReader(encrypted), saltpack.NewKeyring(bob))
+ require.NoError(t, err)
+ require.NotNil(t, key)
+ require.Equal(t, saltpack.EncryptEncoding, enc)
+ require.Equal(t, alice.PublicKey().ID(), key.ID())
+ out, err = ioutil.ReadAll(dstream)
require.NoError(t, err)
require.Equal(t, message, out)
}
@@ -107,17 +139,29 @@ func TestEncryptStreamAnon(t *testing.T) {
// Anon sender
var buf bytes.Buffer
- encrypted, err := saltpack.NewEncryptStream(&buf, nil, bob.ID())
+ stream, err := saltpack.NewEncryptStream(&buf, false, nil, bob.ID())
require.NoError(t, err)
- n, err := encrypted.Write(message)
+ n, err := stream.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
- encrypted.Close()
+ stream.Close()
+ encrypted := copyBytes(buf.Bytes())
- stream, sender, err := saltpack.NewDecryptStream(&buf, saltpack.NewKeyStore(bob))
+ dstream, sender, err := saltpack.NewDecryptStream(bytes.NewReader(encrypted), false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Nil(t, sender)
- out, err := ioutil.ReadAll(stream)
+ out, err := ioutil.ReadAll(dstream)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+
+ dstream, key, enc, err := saltpack.NewReader(bytes.NewReader(encrypted), saltpack.NewKeyring(bob))
+ require.NoError(t, err)
+ require.Nil(t, key)
+ if key != nil {
+ t.Fatal("not nil")
+ }
+ require.Equal(t, saltpack.EncryptEncoding, enc)
+ out, err = ioutil.ReadAll(dstream)
require.NoError(t, err)
require.Equal(t, message, out)
}
@@ -126,10 +170,10 @@ func TestEncryptOpenError(t *testing.T) {
alice := keys.GenerateX25519Key()
bob := keys.GenerateX25519Key()
- encrypted, err := saltpack.Encrypt([]byte("alice's message"), alice, bob.ID())
+ encrypted, err := saltpack.Encrypt([]byte("alice's message"), false, alice, bob.ID())
require.NoError(t, err)
- _, _, err = saltpack.Decrypt(encrypted, saltpack.NewKeyStore())
+ _, _, err = saltpack.Decrypt(encrypted, false, saltpack.NewKeyring())
require.EqualError(t, err, "no decryption key found for message")
}
@@ -139,10 +183,10 @@ func TestEncryptWithEdX25519Key(t *testing.T) {
message := []byte("hi bob")
- encrypted, err := saltpack.Encrypt(message, alice.X25519Key(), bob.ID())
+ encrypted, err := saltpack.Encrypt(message, false, alice.X25519Key(), bob.ID())
require.NoError(t, err)
- out, sender, err := saltpack.Decrypt(encrypted, saltpack.NewKeyStore(bob))
+ out, sender, err := saltpack.Decrypt(encrypted, false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.NotNil(t, sender)
diff --git a/saltpack/saltpack.go b/saltpack/saltpack.go
index ca93f50..d78cf41 100644
--- a/saltpack/saltpack.go
+++ b/saltpack/saltpack.go
@@ -10,21 +10,21 @@ import (
"github.com/pkg/errors"
)
-// KeyStore for Saltpack keys.
-type KeyStore interface {
+// Keyring for Saltpack keys.
+type Keyring interface {
X25519Keys() ([]*keys.X25519Key, error)
}
type saltpack struct {
- ks KeyStore
+ kr Keyring
}
func (s *saltpack) X25519Keys() ([]*keys.X25519Key, error) {
- return s.ks.X25519Keys()
+ return s.kr.X25519Keys()
}
-func newSaltpack(ks KeyStore) *saltpack {
- return &saltpack{ks: ks}
+func newSaltpack(kr Keyring) *saltpack {
+ return &saltpack{kr: kr}
}
type store struct {
@@ -35,8 +35,8 @@ func (s *store) X25519Keys() ([]*keys.X25519Key, error) {
return s.keys, nil
}
-// NewKeyStore creates store for keys.
-func NewKeyStore(keys ...keys.Key) KeyStore {
+// NewKeyring creates keyring for keys.
+func NewKeyring(keys ...keys.Key) Keyring {
return &store{keys: x25519Keys(keys)}
}
@@ -76,7 +76,10 @@ func (s *saltpack) CreateEphemeralKey() (ksaltpack.BoxSecretKey, error) {
// to one of the given Key IDs. Returns the index and the key on success,
// or -1 and nil on failure.
func (s *saltpack) LookupBoxSecretKey(kids [][]byte) (int, ksaltpack.BoxSecretKey) {
- keys, err := s.ks.X25519Keys()
+ if s.kr == nil {
+ return -1, nil
+ }
+ keys, err := s.kr.X25519Keys()
if err != nil {
logger.Warningf("Failed to get x25519 keys: %v", err)
return -1, nil
@@ -105,7 +108,10 @@ func (s *saltpack) LookupBoxPublicKey(kid []byte) ksaltpack.BoxPublicKey {
// receivers via trial and error.
func (s *saltpack) GetAllBoxSecretKeys() []ksaltpack.BoxSecretKey {
logger.Infof("List x25519 keys...")
- keys, err := s.ks.X25519Keys()
+ if s.kr == nil {
+ return []ksaltpack.BoxSecretKey{}
+ }
+ keys, err := s.kr.X25519Keys()
if err != nil {
logger.Warningf("Failed to get x25519 keys: %v", err)
return []ksaltpack.BoxSecretKey{}
diff --git a/saltpack/sign.go b/saltpack/sign.go
index 292a997..926c3a5 100644
--- a/saltpack/sign.go
+++ b/saltpack/sign.go
@@ -1,7 +1,9 @@
package saltpack
import (
+ "bufio"
"io"
+ "os"
"strings"
ksaltpack "github.com/keybase/saltpack"
@@ -10,43 +12,46 @@ import (
)
// Sign ...
-func Sign(b []byte, key *keys.EdX25519Key) ([]byte, error) {
+func Sign(b []byte, armored bool, key *keys.EdX25519Key) ([]byte, error) {
+ if armored {
+ s, err := ksaltpack.SignArmor62(ksaltpack.Version2(), b, newSignKey(key), "")
+ if err != nil {
+ return nil, err
+ }
+ return []byte(s), nil
+ }
return ksaltpack.Sign(ksaltpack.Version2(), b, newSignKey(key))
}
-// SignArmored ...
-func SignArmored(b []byte, key *keys.EdX25519Key) (string, error) {
- return ksaltpack.SignArmor62(ksaltpack.Version2(), b, newSignKey(key), "")
-}
-
// SignDetached ...
-func SignDetached(b []byte, key *keys.EdX25519Key) ([]byte, error) {
+func SignDetached(b []byte, armored bool, key *keys.EdX25519Key) ([]byte, error) {
+ if armored {
+ s, err := ksaltpack.SignDetachedArmor62(ksaltpack.Version2(), b, newSignKey(key), "")
+ if err != nil {
+ return nil, err
+ }
+ return []byte(s), nil
+ }
return ksaltpack.SignDetached(ksaltpack.Version2(), b, newSignKey(key))
}
-// SignArmoredDetached ...
-func SignArmoredDetached(b []byte, key *keys.EdX25519Key) (string, error) {
- return ksaltpack.SignDetachedArmor62(ksaltpack.Version2(), b, newSignKey(key), "")
-}
-
// Verify ...
func Verify(b []byte) ([]byte, keys.ID, error) {
s := &saltpack{}
- spk, out, err := ksaltpack.Verify(signVersionValidator, b, s)
- if err != nil {
- return nil, "", convertSignKeyErr(err)
+ var spk ksaltpack.SigningPublicKey
+ var out []byte
+ var err error
+ enc, armored := detectSign(b)
+ switch enc {
+ case SignEncoding:
+ if armored {
+ spk, out, _, err = ksaltpack.Dearmor62Verify(signVersionValidator, string(b), s)
+ } else {
+ spk, out, err = ksaltpack.Verify(signVersionValidator, b, s)
+ }
+ default:
+ return nil, "", errors.Errorf("invalid data")
}
- signer, err := edX25519KeyID(spk.ToKID())
- if err != nil {
- return nil, "", errors.Wrapf(err, "failed to verify")
- }
- return out, signer, nil
-}
-
-// VerifyArmored ...
-func VerifyArmored(msg string) ([]byte, keys.ID, error) {
- s := &saltpack{}
- spk, out, _, err := ksaltpack.Dearmor62Verify(signVersionValidator, msg, s)
if err != nil {
return nil, "", convertSignKeyErr(err)
}
@@ -60,21 +65,19 @@ func VerifyArmored(msg string) ([]byte, keys.ID, error) {
// VerifyDetached ...
func VerifyDetached(sig []byte, b []byte) (keys.ID, error) {
s := &saltpack{}
- spk, err := ksaltpack.VerifyDetached(signVersionValidator, b, sig, s)
- if err != nil {
- return "", convertSignKeyErr(err)
+ var spk ksaltpack.SigningPublicKey
+ var err error
+ enc, armored := detectSignDetached(sig)
+ switch enc {
+ case SignEncoding:
+ if armored {
+ spk, _, err = ksaltpack.Dearmor62VerifyDetached(signVersionValidator, b, string(sig), s)
+ } else {
+ spk, err = ksaltpack.VerifyDetached(signVersionValidator, b, sig, s)
+ }
+ default:
+ return "", errors.Errorf("invalid data")
}
- signer, err := edX25519KeyID(spk.ToKID())
- if err != nil {
- return "", errors.Wrapf(err, "failed to verify")
- }
- return signer, nil
-}
-
-// VerifyArmoredDetached ...
-func VerifyArmoredDetached(sig string, b []byte) (keys.ID, error) {
- s := &saltpack{}
- spk, _, err := ksaltpack.Dearmor62VerifyDetached(signVersionValidator, b, sig, s)
if err != nil {
return "", convertSignKeyErr(err)
}
@@ -86,43 +89,42 @@ func VerifyArmoredDetached(sig string, b []byte) (keys.ID, error) {
}
// NewSignStream ...
-func NewSignStream(w io.Writer, key *keys.EdX25519Key) (io.WriteCloser, error) {
+func NewSignStream(w io.Writer, armored bool, detached bool, key *keys.EdX25519Key) (io.WriteCloser, error) {
+ if armored && detached {
+ return ksaltpack.NewSignDetachedArmor62Stream(ksaltpack.Version1(), w, newSignKey(key), "")
+ }
+ if armored {
+ return ksaltpack.NewSignArmor62Stream(ksaltpack.Version1(), w, newSignKey(key), "")
+ }
+ if detached {
+ return ksaltpack.NewSignDetachedStream(ksaltpack.Version1(), w, newSignKey(key))
+ }
return ksaltpack.NewSignStream(ksaltpack.Version1(), w, newSignKey(key))
}
-// NewSignArmoredDetachedStream ...
-func NewSignArmoredDetachedStream(w io.Writer, key *keys.EdX25519Key) (io.WriteCloser, error) {
- return ksaltpack.NewSignDetachedArmor62Stream(ksaltpack.Version1(), w, newSignKey(key), "")
-}
-
-// NewSignArmoredStream ...
-func NewSignArmoredStream(w io.Writer, key *keys.EdX25519Key) (io.WriteCloser, error) {
- return ksaltpack.NewSignArmor62Stream(ksaltpack.Version1(), w, newSignKey(key), "")
-}
-
-// NewSignDetachedStream ...
-func NewSignDetachedStream(w io.Writer, key *keys.EdX25519Key) (io.WriteCloser, error) {
- return ksaltpack.NewSignDetachedStream(ksaltpack.Version1(), w, newSignKey(key))
-}
-
// NewVerifyStream ...
func NewVerifyStream(r io.Reader) (io.Reader, keys.ID, error) {
s := &saltpack{}
- spk, reader, err := ksaltpack.NewVerifyStream(signVersionValidator, r, s)
+ buf := bufio.NewReader(r)
+ peek, err := buf.Peek(512)
if err != nil {
- return nil, "", convertSignKeyErr(err)
+ if err != io.EOF {
+ return nil, "", err
+ }
}
- signer, err := edX25519KeyID(spk.ToKID())
- if err != nil {
- return nil, "", errors.Wrapf(err, "failed to verify")
+ var spk ksaltpack.SigningPublicKey
+ var reader io.Reader
+ enc, armored := detectSign(peek)
+ switch enc {
+ case SignEncoding:
+ if armored {
+ spk, reader, _, err = ksaltpack.NewDearmor62VerifyStream(signVersionValidator, buf, s)
+ } else {
+ spk, reader, err = ksaltpack.NewVerifyStream(signVersionValidator, buf, s)
+ }
+ default:
+ err = errors.Errorf("invalid data")
}
- return reader, signer, nil
-}
-
-// NewVerifyArmoredStream ...
-func NewVerifyArmoredStream(r io.Reader) (io.Reader, keys.ID, error) {
- s := &saltpack{}
- spk, reader, _, err := ksaltpack.NewDearmor62VerifyStream(signVersionValidator, r, s)
if err != nil {
return nil, "", convertSignKeyErr(err)
}
@@ -136,23 +138,18 @@ func NewVerifyArmoredStream(r io.Reader) (io.Reader, keys.ID, error) {
// VerifyDetachedReader ...
func VerifyDetachedReader(sig []byte, r io.Reader) (keys.ID, error) {
s := &saltpack{}
- spk, err := ksaltpack.VerifyDetachedReader(signVersionValidator, r, sig, s)
- if err != nil {
- return "", convertSignKeyErr(err)
- }
- signer, err := edX25519KeyID(spk.ToKID())
- if err != nil {
- return "", errors.Wrapf(err, "failed to verify")
- }
- return signer, nil
-}
-
-// VerifyArmoredDetachedReader ...
-func VerifyArmoredDetachedReader(sig string, r io.Reader) (keys.ID, error) {
- s := &saltpack{}
- spk, _, err := ksaltpack.Dearmor62VerifyDetachedReader(signVersionValidator, r, sig, s)
- if err != nil {
- return "", convertSignKeyErr(err)
+ var spk ksaltpack.SigningPublicKey
+ var err error
+ enc, armored := detectSignDetached(sig)
+ switch enc {
+ case SignEncoding:
+ if armored {
+ spk, _, err = ksaltpack.Dearmor62VerifyDetachedReader(signVersionValidator, r, string(sig), s)
+ } else {
+ spk, err = ksaltpack.VerifyDetachedReader(signVersionValidator, r, sig, s)
+ }
+ default:
+ return "", errors.Errorf("invalid data")
}
signer, err := edX25519KeyID(spk.ToKID())
if err != nil {
@@ -169,3 +166,132 @@ func StripBefore(message string) string {
}
return message[n:]
}
+
+// SignFile signs a file.
+func SignFile(in string, out string, key *keys.EdX25519Key, armored bool, detached bool) error {
+ logger.Infof("Signing %s to %s", in, out)
+
+ if in == "" {
+ return errors.Errorf("in not specified")
+ }
+ if out == "" {
+ return errors.Errorf("out not specified")
+ }
+
+ outTmp := out + ".tmp"
+ outFile, err := os.Create(outTmp)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ _ = outFile.Close()
+ _ = os.Remove(outTmp)
+ }()
+ writer := bufio.NewWriter(outFile)
+
+ logger.Debugf("Sign armored=%t detached=%t", armored, detached)
+ stream, err := NewSignStream(writer, armored, detached, key)
+ if err != nil {
+ return err
+ }
+
+ inFile, err := os.Open(in) // #nosec
+ if err != nil {
+ return err
+ }
+ defer func() {
+ _ = inFile.Close()
+ }()
+ reader := bufio.NewReader(inFile)
+ if _, err := reader.WriteTo(stream); err != nil {
+ return err
+ }
+
+ if err := stream.Close(); err != nil {
+ return err
+ }
+ if err := writer.Flush(); err != nil {
+ return err
+ }
+ if err := inFile.Close(); err != nil {
+ return err
+ }
+ if err := outFile.Close(); err != nil {
+ return err
+ }
+
+ if err := os.Rename(outTmp, out); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// VerifyFile outputs verified file from in path.
+func VerifyFile(in string, out string) (keys.ID, error) {
+ logger.Infof("Verify %s to %s", in, out)
+ if in == "" {
+ return "", errors.Errorf("in not specified")
+ }
+ if out == "" {
+ return "", errors.Errorf("out not specified")
+ }
+
+ inFile, err := os.Open(in) // #nosec
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ _ = inFile.Close()
+ }()
+ reader := bufio.NewReader(inFile)
+
+ verifyReader, kid, err := NewVerifyStream(reader)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to verify file")
+ }
+
+ outTmp := out + ".tmp"
+ outFile, err := os.Create(outTmp)
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ _ = outFile.Close()
+ _ = os.Remove(outTmp)
+ }()
+
+ writer := bufio.NewWriter(outFile)
+
+ if _, err := writer.ReadFrom(verifyReader); err != nil {
+ return "", err
+ }
+ if err := writer.Flush(); err != nil {
+ return "", err
+ }
+ if err := inFile.Close(); err != nil {
+ return "", err
+ }
+ if err := outFile.Close(); err != nil {
+ return "", err
+ }
+
+ if err := os.Rename(outTmp, out); err != nil {
+ return "", err
+ }
+
+ return kid, nil
+}
+
+// VerifyFileDetached verifies file at path with signature.
+func VerifyFileDetached(sig []byte, path string) (keys.ID, error) {
+ file, err := os.Open(path) // #nosec
+ if err != nil {
+ return "", err
+ }
+ defer func() {
+ _ = file.Close()
+ }()
+ reader := bufio.NewReader(file)
+ return VerifyDetachedReader(sig, reader)
+}
diff --git a/saltpack/sign_examples_test.go b/saltpack/sign_examples_test.go
index be4279d..63fb922 100644
--- a/saltpack/sign_examples_test.go
+++ b/saltpack/sign_examples_test.go
@@ -13,7 +13,7 @@ func ExampleSign() {
message := []byte("hi from alice")
- sig, err := saltpack.SignArmored(message, alice)
+ sig, err := saltpack.Sign(message, true, alice)
if err != nil {
log.Fatal(err)
}
@@ -26,7 +26,7 @@ func ExampleSignDetached() {
message := []byte("hi from alice")
- sig, err := saltpack.SignArmoredDetached(message, alice)
+ sig, err := saltpack.SignDetached(message, true, alice)
if err != nil {
log.Fatal(err)
}
@@ -35,15 +35,15 @@ func ExampleSignDetached() {
func ExampleVerify() {
aliceID := keys.ID("kex1w2jep8dkr2s0g9kx5g6xe3387jslnlj08yactvn8xdtrx4cnypjq9rpnux")
- signed := `BEGIN SALTPACK SIGNED MESSAGE.
+ signed := []byte(`BEGIN SALTPACK SIGNED MESSAGE.
kXR7VktZdyH7rvq v5wcIkHbs7mPCSd NhKLR9E0K47y29T QkuYinHym6EfZwL
1TwgxI3RQ52fHg5 1FzmLOMghcYLcV7 i0l0ovabGhxGrEl z7WuI4O3xMU5saq
U28RqUnKNroATPO 5rn2YyQcut2SeMn lXJBlDqRv9WyxjG M0PcKvsAsvmid1m
cqA4TCjz5V9VpuO zuIQ55lRQLeP5kU aWFxq5Nl8WsPqlR RdX86OuTbaKUvKI
wdNd6ISacrT0I82 qZ71sc7sTxiMxoI P43uCGaAZZ3Ab62 vR8N6WQPE8.
- END SALTPACK SIGNED MESSAGE.`
+ END SALTPACK SIGNED MESSAGE.`)
- out, signer, err := saltpack.VerifyArmored(signed)
+ out, signer, err := saltpack.Verify(signed)
if err != nil {
log.Fatal(err)
}
diff --git a/saltpack/sign_test.go b/saltpack/sign_test.go
index 6aafcd8..2e2842c 100644
--- a/saltpack/sign_test.go
+++ b/saltpack/sign_test.go
@@ -3,6 +3,8 @@ package saltpack_test
import (
"bytes"
"io/ioutil"
+ "os"
+ "path/filepath"
"testing"
"github.com/keys-pub/keys"
@@ -15,7 +17,7 @@ func TestSignVerify(t *testing.T) {
message := []byte("hi")
- sig, err := saltpack.Sign(message, alice)
+ sig, err := saltpack.Sign(message, false, alice)
require.NoError(t, err)
out, signer, err := saltpack.Verify(sig)
@@ -23,7 +25,7 @@ func TestSignVerify(t *testing.T) {
require.Equal(t, message, out)
require.Equal(t, alice.PublicKey().ID(), signer)
- sig, err = saltpack.SignDetached(message, alice)
+ sig, err = saltpack.SignDetached(message, false, alice)
require.NoError(t, err)
signer, err = saltpack.VerifyDetached(sig, message)
@@ -37,12 +39,20 @@ func TestSignVerifyArmored(t *testing.T) {
message := []byte("hi")
- sig, err := saltpack.SignArmored(message, alice)
+ sig, err := saltpack.Sign(message, true, alice)
require.NoError(t, err)
- messageOut, signer, err := saltpack.VerifyArmored(sig)
+ out, signer, err := saltpack.Verify(sig)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+ require.Equal(t, alice.PublicKey().ID(), signer)
+
+ sig, err = saltpack.SignDetached(message, true, alice)
require.NoError(t, err)
- require.Equal(t, message, messageOut)
+
+ signer, err = saltpack.VerifyDetached(sig, message)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
require.Equal(t, alice.PublicKey().ID(), signer)
}
@@ -52,7 +62,7 @@ func TestSignVerifyStream(t *testing.T) {
message := []byte("I'm alice")
var buf bytes.Buffer
- signed, err := saltpack.NewSignStream(&buf, alice)
+ signed, err := saltpack.NewSignStream(&buf, false, false, alice)
require.NoError(t, err)
n, err := signed.Write(message)
require.NoError(t, err)
@@ -68,7 +78,7 @@ func TestSignVerifyStream(t *testing.T) {
require.Equal(t, message, out)
var buf2 bytes.Buffer
- signed2, err := saltpack.NewSignArmoredStream(&buf2, alice)
+ signed2, err := saltpack.NewSignStream(&buf2, true, false, alice)
require.NoError(t, err)
n, err = signed2.Write(message)
require.NoError(t, err)
@@ -76,7 +86,7 @@ func TestSignVerifyStream(t *testing.T) {
signed2.Close()
reader = bytes.NewReader(buf2.Bytes())
- stream, signer, err = saltpack.NewVerifyArmoredStream(reader)
+ stream, signer, err = saltpack.NewVerifyStream(reader)
require.NoError(t, err)
require.Equal(t, alice.PublicKey().ID(), signer)
out, err = ioutil.ReadAll(stream)
@@ -85,7 +95,7 @@ func TestSignVerifyStream(t *testing.T) {
// Sign detached
var buf3 bytes.Buffer
- signed3, err := saltpack.NewSignDetachedStream(&buf3, alice)
+ signed3, err := saltpack.NewSignStream(&buf3, false, true, alice)
require.NoError(t, err)
_, err = signed3.Write(message)
require.NoError(t, err)
@@ -98,18 +108,91 @@ func TestSignVerifyStream(t *testing.T) {
// Sign armored/detached
var buf4 bytes.Buffer
- signed4, err := saltpack.NewSignArmoredDetachedStream(&buf4, alice)
+ signed4, err := saltpack.NewSignStream(&buf4, true, true, alice)
require.NoError(t, err)
_, err = signed4.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
signed4.Close()
- signer, err = saltpack.VerifyArmoredDetachedReader(buf4.String(), bytes.NewBuffer(message))
+ signer, err = saltpack.VerifyDetachedReader(buf4.Bytes(), bytes.NewBuffer(message))
require.NoError(t, err)
require.Equal(t, alice.PublicKey().ID(), signer)
}
+func TestSignVerifyFile(t *testing.T) {
+ testSignVerifyFile(t, false)
+ testSignVerifyFile(t, true)
+}
+
+func testSignVerifyFile(t *testing.T, armored bool) {
+ var err error
+ alice := keys.GenerateEdX25519Key()
+ in := filepath.Join(os.TempDir(), keys.RandFileName())
+ data := bytes.Repeat([]byte{0x01}, 16*1024)
+ err = ioutil.WriteFile(in, data, 0600)
+ require.NoError(t, err)
+ out := in + ".signed"
+ outVerified := in + ".verified"
+ defer func() {
+ _ = os.Remove(in)
+ _ = os.Remove(out)
+ _ = os.Remove(outVerified)
+ }()
+
+ err = saltpack.SignFile(in, out, alice, armored, false)
+ require.NoError(t, err)
+
+ kid, err := saltpack.VerifyFile(out, outVerified)
+ require.NoError(t, err)
+ require.Equal(t, alice.ID(), kid)
+ b, err := ioutil.ReadFile(outVerified)
+ require.NoError(t, err)
+ require.Equal(t, data, b)
+}
+
+func TestSignFileErrors(t *testing.T) {
+ var err error
+ alice := keys.GenerateEdX25519Key()
+ err = saltpack.SignFile("notfound", "notfound.sig", alice, true, true)
+ require.EqualError(t, err, "open notfound: no such file or directory")
+}
+
+func TestVerifyFileErrors(t *testing.T) {
+ var err error
+ _, err = saltpack.VerifyFile("notfound.signed", "notfound")
+ require.EqualError(t, err, "open notfound.signed: no such file or directory")
+}
+
+func TestSignVerifyFileDetached(t *testing.T) {
+ testSignVerifyFileDetached(t, false)
+ testSignVerifyFileDetached(t, true)
+}
+
+func testSignVerifyFileDetached(t *testing.T, armored bool) {
+ var err error
+ alice := keys.GenerateEdX25519Key()
+ in := filepath.Join(os.TempDir(), keys.RandFileName())
+ data := bytes.Repeat([]byte{0x01}, 16*1024)
+ err = ioutil.WriteFile(in, data, 0600)
+ require.NoError(t, err)
+ out := in + ".sig"
+ defer func() {
+ _ = os.Remove(in)
+ _ = os.Remove(out)
+ }()
+
+ err = saltpack.SignFile(in, out, alice, armored, true)
+ require.NoError(t, err)
+
+ sig, err := ioutil.ReadFile(out)
+ require.NoError(t, err)
+
+ kid, err := saltpack.VerifyFileDetached(sig, in)
+ require.NoError(t, err)
+ require.Equal(t, alice.ID(), kid)
+}
+
func TestStripBefore(t *testing.T) {
sig := "BEGIN SALTPACK SIGNED MESSAGE. XXXXXXXX END SALTPACK SIGNED MESSAGE."
message := saltpack.StripBefore("Some text in the beginning to ignore: " + sig)
diff --git a/saltpack/signcrypt.go b/saltpack/signcrypt.go
index 3e25f28..11ee995 100644
--- a/saltpack/signcrypt.go
+++ b/saltpack/signcrypt.go
@@ -11,7 +11,7 @@ import (
// Signcrypt to recipients.
// https://saltpack.org/signcryption-format
-func Signcrypt(b []byte, sender *keys.EdX25519Key, recipients ...keys.ID) ([]byte, error) {
+func Signcrypt(b []byte, armored bool, sender *keys.EdX25519Key, recipients ...keys.ID) ([]byte, error) {
recs, err := boxPublicKeys(recipients)
if err != nil {
return nil, err
@@ -20,20 +20,14 @@ func Signcrypt(b []byte, sender *keys.EdX25519Key, recipients ...keys.ID) ([]byt
return nil, errors.Errorf("no sender specified")
}
sk := newSignKey(sender)
- return ksaltpack.SigncryptSeal(b, ephemeralKeyCreator{}, sk, recs, nil)
-}
-
-// SigncryptArmored to recipients.
-func SigncryptArmored(b []byte, sender *keys.EdX25519Key, recipients ...keys.ID) (string, error) {
- recs, err := boxPublicKeys(recipients)
- if err != nil {
- return "", err
+ if armored {
+ s, err := ksaltpack.SigncryptArmor62Seal(b, ephemeralKeyCreator{}, sk, recs, nil, "")
+ if err != nil {
+ return nil, err
+ }
+ return []byte(s), nil
}
- if sender == nil {
- return "", errors.Errorf("no sender specified")
- }
- sk := newSignKey(sender)
- return ksaltpack.SigncryptArmor62Seal(b, ephemeralKeyCreator{}, sk, recs, nil, "")
+ return ksaltpack.SigncryptSeal(b, ephemeralKeyCreator{}, sk, recs, nil)
}
func edx25519SenderKey(senderPub ksaltpack.SigningPublicKey) (*keys.EdX25519PublicKey, error) {
@@ -42,31 +36,23 @@ func edx25519SenderKey(senderPub ksaltpack.SigningPublicKey) (*keys.EdX25519Publ
}
b := senderPub.ToKID()
if len(b) != 32 {
- return nil, errors.Errorf("invalid (edx25519) sender key")
+ return nil, errors.Errorf("invalid edx25519 sender key")
}
return keys.NewEdX25519PublicKey(keys.Bytes32(b)), nil
}
// SigncryptOpen ...
-func SigncryptOpen(b []byte, ks KeyStore) ([]byte, *keys.EdX25519PublicKey, error) {
- s := newSaltpack(ks)
- spk, out, err := ksaltpack.SigncryptOpen(b, s, nil)
- if err != nil {
- return nil, nil, convertSignKeyErr(err)
+func SigncryptOpen(b []byte, armored bool, kr Keyring) ([]byte, *keys.EdX25519PublicKey, error) {
+ s := newSaltpack(kr)
+ var spk ksaltpack.SigningPublicKey
+ var out []byte
+ var err error
+ if armored {
+ spk, out, _, err = ksaltpack.Dearmor62SigncryptOpen(string(b), s, nil)
+ } else {
+ spk, out, err = ksaltpack.SigncryptOpen(b, s, nil)
}
- sender, err := edx25519SenderKey(spk)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "failed to signcrypt open")
- }
- return out, sender, nil
-}
-
-// SigncryptArmoredOpen ...
-func SigncryptArmoredOpen(str string, ks KeyStore) ([]byte, *keys.EdX25519PublicKey, error) {
- s := newSaltpack(ks)
- // TODO: Casting to string could be a performance issue
- spk, out, _, err := ksaltpack.Dearmor62SigncryptOpen(str, s, nil)
if err != nil {
return nil, nil, convertSignKeyErr(err)
}
@@ -78,42 +64,29 @@ func SigncryptArmoredOpen(str string, ks KeyStore) ([]byte, *keys.EdX25519Public
}
// NewSigncryptStream creates a signcrypt stream.
-func NewSigncryptStream(w io.Writer, sender *keys.EdX25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
+func NewSigncryptStream(w io.Writer, armored bool, sender *keys.EdX25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
recs, err := boxPublicKeys(recipients)
if err != nil {
return nil, err
}
- return ksaltpack.NewSigncryptSealStream(w, ephemeralKeyCreator{}, newSignKey(sender), recs, nil)
-}
-
-// NewSigncryptArmoredStream creates a signcrypt stream.
-func NewSigncryptArmoredStream(w io.Writer, sender *keys.EdX25519Key, recipients ...keys.ID) (io.WriteCloser, error) {
- recs, err := boxPublicKeys(recipients)
- if err != nil {
- return nil, err
+ if armored {
+ return ksaltpack.NewSigncryptArmor62SealStream(w, ephemeralKeyCreator{}, newSignKey(sender), recs, nil, "")
}
- return ksaltpack.NewSigncryptArmor62SealStream(w, ephemeralKeyCreator{}, newSignKey(sender), recs, nil, "")
+ return ksaltpack.NewSigncryptSealStream(w, ephemeralKeyCreator{}, newSignKey(sender), recs, nil)
}
// NewSigncryptOpenStream creates a signcrypt open stream.
-func NewSigncryptOpenStream(r io.Reader, ks KeyStore) (io.Reader, *keys.EdX25519PublicKey, error) {
- s := newSaltpack(ks)
- spk, stream, err := ksaltpack.NewSigncryptOpenStream(r, s, nil)
- if err != nil {
- return nil, nil, convertSignKeyErr(err)
- }
- sender, err := edx25519SenderKey(spk)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "failed to signcrypt open")
- }
- return stream, sender, nil
-}
+func NewSigncryptOpenStream(r io.Reader, armored bool, kr Keyring) (io.Reader, *keys.EdX25519PublicKey, error) {
+ s := newSaltpack(kr)
-// NewSigncryptArmoredOpenStream ...
-func NewSigncryptArmoredOpenStream(r io.Reader, ks KeyStore) (io.Reader, *keys.EdX25519PublicKey, error) {
- s := newSaltpack(ks)
- // TODO: Specifying nil for resolver will panic if box keys not found
- spk, stream, _, err := ksaltpack.NewDearmor62SigncryptOpenStream(r, s, nil)
+ var spk ksaltpack.SigningPublicKey
+ var stream io.Reader
+ var err error
+ if armored {
+ spk, stream, _, err = ksaltpack.NewDearmor62SigncryptOpenStream(r, s, nil)
+ } else {
+ spk, stream, err = ksaltpack.NewSigncryptOpenStream(r, s, nil)
+ }
if err != nil {
return nil, nil, convertSignKeyErr(err)
}
diff --git a/saltpack/signcrypt_test.go b/saltpack/signcrypt_test.go
index 16b5051..4f051a0 100644
--- a/saltpack/signcrypt_test.go
+++ b/saltpack/signcrypt_test.go
@@ -16,70 +16,95 @@ func TestSigncrypt(t *testing.T) {
message := []byte("hi bob")
- encrypted, err := saltpack.Signcrypt(message, alice, bob.ID())
+ encrypted, err := saltpack.Signcrypt(message, false, alice, bob.ID())
require.NoError(t, err)
- out, sender, err := saltpack.SigncryptOpen(encrypted, saltpack.NewKeyStore(bob))
+ out, sender, err := saltpack.SigncryptOpen(encrypted, false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- encrypted2, err := saltpack.SigncryptArmored(message, alice, bob.ID())
+ encrypted2, err := saltpack.Signcrypt(message, true, alice, bob.ID())
require.NoError(t, err)
- out, sender, err = saltpack.SigncryptArmoredOpen(encrypted2, saltpack.NewKeyStore(bob))
+ out, sender, err = saltpack.SigncryptOpen(encrypted2, true, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.Equal(t, message, out)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- _, err = saltpack.Signcrypt(message, alice, keys.ID(""))
+ _, err = saltpack.Signcrypt(message, false, alice, keys.ID(""))
require.EqualError(t, err, "invalid recipient: empty id")
- _, err = saltpack.Signcrypt(message, nil, bob.ID())
+ _, err = saltpack.Signcrypt(message, false, nil, bob.ID())
require.EqualError(t, err, "no sender specified")
// Duplicate recipient
- _, err = saltpack.Signcrypt(message, alice, bob.ID(), bob.ID())
+ _, err = saltpack.Signcrypt(message, false, alice, bob.ID(), bob.ID())
require.NoError(t, err)
}
func TestSigncryptStream(t *testing.T) {
alice := keys.GenerateEdX25519Key()
bob := keys.GenerateEdX25519Key()
-
message := []byte("hi bob")
var buf bytes.Buffer
- encrypted, err := saltpack.NewSigncryptStream(&buf, alice, bob.ID())
+ stream, err := saltpack.NewSigncryptStream(&buf, false, alice, bob.ID())
require.NoError(t, err)
- n, err := encrypted.Write(message)
+ n, err := stream.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
- encrypted.Close()
+ stream.Close()
+ encrypted := copyBytes(buf.Bytes())
- stream, sender, err := saltpack.NewSigncryptOpenStream(&buf, saltpack.NewKeyStore(bob))
+ dstream, sender, err := saltpack.NewSigncryptOpenStream(bytes.NewReader(encrypted), false, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- out, err := ioutil.ReadAll(stream)
+ out, err := ioutil.ReadAll(dstream)
require.NoError(t, err)
require.Equal(t, message, out)
- var buf2 bytes.Buffer
- encrypted2, err := saltpack.NewSigncryptArmoredStream(&buf2, alice, bob.ID())
+ dstream, key, enc, err := saltpack.NewReader(bytes.NewReader(encrypted), saltpack.NewKeyring(bob))
require.NoError(t, err)
- n, err = encrypted2.Write(message)
+ require.NotNil(t, key)
+ require.Equal(t, saltpack.SigncryptEncoding, enc)
+ require.Equal(t, alice.PublicKey().ID(), key.ID())
+ out, err = ioutil.ReadAll(dstream)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+}
+
+func TestSigncryptArmoredStream(t *testing.T) {
+ alice := keys.GenerateEdX25519Key()
+ bob := keys.GenerateEdX25519Key()
+ message := []byte("hi bob")
+
+ var buf bytes.Buffer
+ stream, err := saltpack.NewSigncryptStream(&buf, true, alice, bob.ID())
+ require.NoError(t, err)
+ n, err := stream.Write(message)
require.NoError(t, err)
require.Equal(t, len(message), n)
- encrypted2.Close()
+ stream.Close()
+ encrypted := copyBytes(buf.Bytes())
- stream, sender, err = saltpack.NewSigncryptArmoredOpenStream(&buf2, saltpack.NewKeyStore(bob))
+ dstream, sender, err := saltpack.NewSigncryptOpenStream(bytes.NewReader(encrypted), true, saltpack.NewKeyring(bob))
require.NoError(t, err)
require.NotNil(t, sender)
require.Equal(t, alice.PublicKey().ID(), sender.ID())
- out, err = ioutil.ReadAll(stream)
+ out, err := ioutil.ReadAll(dstream)
+ require.NoError(t, err)
+ require.Equal(t, message, out)
+
+ dstream, key, enc, err := saltpack.NewReader(bytes.NewReader(encrypted), saltpack.NewKeyring(bob))
+ require.NoError(t, err)
+ require.NotNil(t, key)
+ require.Equal(t, saltpack.SigncryptEncoding, enc)
+ require.Equal(t, alice.PublicKey().ID(), key.ID())
+ out, err = ioutil.ReadAll(dstream)
require.NoError(t, err)
require.Equal(t, message, out)
}
@@ -88,9 +113,9 @@ func TestSigncryptOpenError(t *testing.T) {
alice := keys.GenerateEdX25519Key()
bob := keys.GenerateEdX25519Key()
- encrypted, err := saltpack.Signcrypt([]byte("alice's message"), alice, bob.ID())
+ encrypted, err := saltpack.Signcrypt([]byte("alice's message"), false, alice, bob.ID())
require.NoError(t, err)
- _, _, err = saltpack.SigncryptOpen(encrypted, saltpack.NewKeyStore())
+ _, _, err = saltpack.SigncryptOpen(encrypted, false, saltpack.NewKeyring())
require.EqualError(t, err, "no decryption key found for message")
}
From 4ddc8c1321d97bed13492a2a6b1ab570c846443b Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Sun, 26 Jul 2020 17:29:57 -0700
Subject: [PATCH 2/4] Update detect_test.go
---
saltpack/detect_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/saltpack/detect_test.go b/saltpack/detect_test.go
index 228cb3d..e545464 100644
--- a/saltpack/detect_test.go
+++ b/saltpack/detect_test.go
@@ -31,7 +31,7 @@ func TestDetectEncrypt(t *testing.T) {
require.NoError(t, err)
enc, armored = detectEncrypt([]byte(signcrypted))
require.Equal(t, SigncryptEncoding, enc)
- require.True(t, armored)
+ require.False(t, armored)
out, err = Signcrypt(message, true, alice, bob.ID())
require.NoError(t, err)
From 7a5a5080996cdee204a5b4405ac95a29a2ccb83f Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Sun, 26 Jul 2020 17:34:32 -0700
Subject: [PATCH 3/4] Update sign.go
---
saltpack/sign.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/saltpack/sign.go b/saltpack/sign.go
index 926c3a5..8a0ee64 100644
--- a/saltpack/sign.go
+++ b/saltpack/sign.go
@@ -151,6 +151,9 @@ func VerifyDetachedReader(sig []byte, r io.Reader) (keys.ID, error) {
default:
return "", errors.Errorf("invalid data")
}
+ if err != nil {
+ return "", convertSignKeyErr(err)
+ }
signer, err := edX25519KeyID(spk.ToKID())
if err != nil {
return "", errors.Wrapf(err, "failed to verify")
From 259df6599ebc15983d306c5390b4be365f7f0d0f Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Sun, 26 Jul 2020 17:41:41 -0700
Subject: [PATCH 4/4] Update sign_test.go
---
saltpack/sign_test.go | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/saltpack/sign_test.go b/saltpack/sign_test.go
index 2e2842c..ee7a0a0 100644
--- a/saltpack/sign_test.go
+++ b/saltpack/sign_test.go
@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
+ "runtime"
"testing"
"github.com/keys-pub/keys"
@@ -152,6 +153,9 @@ func testSignVerifyFile(t *testing.T, armored bool) {
}
func TestSignFileErrors(t *testing.T) {
+ if runtime.GOOS != "darwin" {
+ t.Skip()
+ }
var err error
alice := keys.GenerateEdX25519Key()
err = saltpack.SignFile("notfound", "notfound.sig", alice, true, true)
@@ -159,6 +163,9 @@ func TestSignFileErrors(t *testing.T) {
}
func TestVerifyFileErrors(t *testing.T) {
+ if runtime.GOOS != "darwin" {
+ t.Skip()
+ }
var err error
_, err = saltpack.VerifyFile("notfound.signed", "notfound")
require.EqualError(t, err, "open notfound.signed: no such file or directory")