diff --git a/encode_test.go b/encode_test.go index 48e4fe4..c5745db 100644 --- a/encode_test.go +++ b/encode_test.go @@ -1,6 +1,8 @@ package keys_test import ( + "fmt" + "log" "testing" "github.com/keys-pub/keys" @@ -22,6 +24,19 @@ func TestEncodeKeyToSaltpack(t *testing.T) { require.Equal(t, sk.Bytes(), skOut.Bytes()) } +func ExampleDecodeSaltpackKey() { + key := `BEGIN X25519 KEY MESSAGE. + umCRo9iHIudLWoz 4Ugt0hUXQVJ7lhV p7A9mb3kOTg6PeV fhqetAc9ZOUjagi + 91gENEkp0xfjF2E Tyakwe90kzo1FNT gRacWRL5B59strN OoZYHQooqvlMKM. + END X25519 KEY MESSAGE.` + bob, err := keys.DecodeSaltpackKey(key, "", true) + if err != nil { + log.Fatal(err) + } + fmt.Printf("bob: %s\n", bob.ID()) + // Output: bob: kbx18x22l7nemmxcj76f9l3aaflc5487lp5u5q778gpe3t3wzhlqvu8qxa9z07 +} + func TestEncodeKeyDecodeKey(t *testing.T) { sk := keys.GenerateEdX25519Key() diff --git a/noise/README.md b/noise/README.md index bcc2391..1f8e6d5 100644 --- a/noise/README.md +++ b/noise/README.md @@ -1,8 +1,6 @@ # Noise -This package helps setup a Noise handshake using X25519 keys. - -For more details visit **[keys.pub](https://keys.pub)**. +The [noise package](https://github.com/keys-pub/keys/blob/master/noise) helps setup a Noise handshake using X25519 keys. The default cipher suite used is: Curve25519 ECDH, ChaCha20-Poly1305 AEAD, BLAKE2b hash. @@ -23,70 +21,8 @@ The order of the handshake writes/reads should be: When the handshake is complete, use the Cipher to Encrypt/Decrypt. -See [noisprotocol.org](http://www.noiseprotocol.org) for more info. - -The following example completes a handshake using two X25519 keys (Alice and Bob), and -uses the cipher to encrypt and decrypt. - -```go -import ( - "github.com/keys-pub/keys" - "github.com/keys-pub/keys/noise" -) - -... - -alice := keys.GenerateX25519Key() -bob := keys.GenerateX25519Key() - -na, err := noise.NewHandshake(alice, bob.PublicKey(), true) -if err != nil { - log.Fatal(err) -} - -nb, err := noise.NewHandshake(bob, alice.PublicKey(), false) -if err != nil { - log.Fatal(err) -} - -// -> s -// <- s -ha, err := na.Write(nil) -if err != nil { - log.Fatal(err) -} -if _, err := nb.Read(ha); err != nil { - log.Fatal(err) -} -// -> e, es, ss -// <- e, ee, se -hb, err := nb.Write(nil) -if err != nil { - log.Fatal(err) -} -if _, err := na.Read(hb); err != nil { - log.Fatal(err) -} - -// transport I -> R -ca, err := na.Cipher() -if err != nil { - log.Fatal(err) -} -encrypted, err := ca.Encrypt(nil, nil, []byte("hello")) -if err != nil { - log.Fatal(err) -} +See [noiseprotocol.org](http://www.noiseprotocol.org) for more info. -cb, err := nb.Cipher() -if err != nil { - log.Fatal(err) -} -decrypted, err := cb.Decrypt(nil, nil, encrypted) -if err != nil { - log.Fatal(err) -} +## Examples -fmt.Printf("%s", string(decrypted)) -// Output: hello -``` +- [Handshake + Encrypt/Decrypt](https://github.com/keys-pub/keys/blob/master/noise/example_test.go) diff --git a/noise/noise.go b/noise/noise.go index 57432ee..7a4ab2d 100644 --- a/noise/noise.go +++ b/noise/noise.go @@ -14,7 +14,7 @@ type Cipher interface { Decrypt(out, ad, ciphertext []byte) ([]byte, error) } -// Noise protocol for keys.pub. +// Handshake using noise protocol. // See http://www.noiseprotocol.org/. type Handshake struct { initiator bool @@ -32,16 +32,16 @@ type Handshake struct { // Curve25519 ECDH, ChaCha20-Poly1305 AEAD, BLAKE2b hash. // // The handshake uses the KK pattern: -// K = Static key for initiator Known to responder -// K = Static key for responder Known to initiator +// - K = Static key for initiator Known to responder +// - K = Static key for responder Known to initiator // // One of the Noise participants should be the initiator. // // The order of the handshake writes/reads should be: -// (1) Initiator: Write -// (2) Responder: Read -// (3) Initiator: Read -// (4) Responder: Write +// - (1) Initiator: Write +// - (2) Responder: Read +// - (3) Initiator: Read +// - (4) Responder: Write // // When the handshake is complete, use the Cipher to Encrypt/Decrypt. // diff --git a/saltpack/README.md b/saltpack/README.md index 304b493..f0c77bb 100644 --- a/saltpack/README.md +++ b/saltpack/README.md @@ -6,5 +6,6 @@ This [github.com/keys-pub/keys/saltpack](https://github.com/keys-pub/keys/tree/m ## Examples -- [Encrypt + Decrypt](https://github.com/keys-pub/keys/blob/master/saltpack/encrypt_examples_test.go) +- [Encrypt/Decrypt](https://github.com/keys-pub/keys/blob/master/saltpack/encrypt_examples_test.go) +- [Signcrypt/Open](https://github.com/keys-pub/keys/blob/master/saltpack/signcrypt_examples_test.go) - [Sign + Verify](https://github.com/keys-pub/keys/blob/master/saltpack/sign_examples_test.go) diff --git a/saltpack/encrypt_examples_test.go b/saltpack/encrypt_examples_test.go index a3f6b88..d87c5de 100644 --- a/saltpack/encrypt_examples_test.go +++ b/saltpack/encrypt_examples_test.go @@ -9,40 +9,36 @@ import ( ) func ExampleEncrypt() { - alice := keys.GenerateX25519Key() - bob := keys.GenerateX25519Key() + alice := keys.NewX25519KeyFromSeed(testSeed(0x01)) + bobID := keys.ID("kbx1e6xn45wvkce7c7msc9upffw8dmxs9959q5xng369hgzcwrjc04vs8u82mj") message := []byte("hi bob") + fmt.Printf("alice: %s\n", alice.ID()) + fmt.Printf("bob: %s\n", bobID) + // Encrypt from alice to bob - encrypted, err := saltpack.Encrypt(message, true, alice, bob.ID()) + encrypted, err := saltpack.Encrypt(message, true, alice, bobID) if err != nil { log.Fatal(err) } - fmt.Printf("%d", len(encrypted)) - // Output: 375 + fmt.Printf("%s...\n", encrypted[0:30]) + // Output: + // alice: kbx15nsf9y4k28p83wth93tf7hafhvfajp45d2mge80ems45gz0c5gys57cytk + // bob: kbx1e6xn45wvkce7c7msc9upffw8dmxs9959q5xng369hgzcwrjc04vs8u82mj + // BEGIN SALTPACK ENCRYPTED MESSA... } func ExampleDecrypt() { - // Message from ExampleEncrypt - aliceID := keys.ID("kbx17jhqvdrgdyruyseuaat0rerj7ep4n63n4klufzxtzmk9p3d944gs4fg39g") - 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. - umCRo9iHIudLWoz 4Ugt0hUXQVJ7lhV p7A9mb3kOTg6PeV fhqetAc9ZOUjagi - 91gENEkp0xfjF2E Tyakwe90kzo1FNT gRacWRL5B59strN OoZYHQooqvlMKM. - END X25519 KEY MESSAGE.` - bob, err := keys.DecodeSaltpackKey(key, "", true) - if err != nil { - log.Fatal(err) - } + aliceID := keys.ID("kbx15nsf9y4k28p83wth93tf7hafhvfajp45d2mge80ems45gz0c5gys57cytk") + encrypted := []byte(`BEGIN SALTPACK ENCRYPTED MESSAGE. + kcJn5brvybfNjz6 D5ll2Nk0YnkdsxV g8EmizCg7a8zpHt Wh3GEuw5BrCUP2u N00ZdO6tTiw5NAl + M2M9M0ErPX1xAmK Cfh7IG2sQfbxIH3 OmQwZxc13hjpoG4 1NWwphYm2HR7i1Z LOdCpf8kbf5UFSC + eEUlInuYgfWLJdT 7y3iBbCvlejdmJW aSRZAgrmiEqYfTL a0NzUyir4lT4h9G DUYEGWA8JD3cuCh + Xfi0TNH5BlgOnBm 65o53Xaztwpv6Q4 BMM6AoTyMYk9iR3 5ybluVFI5DJq0YP N6t. + END SALTPACK ENCRYPTED MESSAGE.`) + + bob := keys.NewX25519KeyFromSeed(testSeed(0x02)) // Bob decrypts out, sender, err := saltpack.Decrypt(encrypted, true, saltpack.NewKeyring(bob)) diff --git a/saltpack/keybase_test.go b/saltpack/keybase_test.go new file mode 100644 index 0000000..ac369b1 --- /dev/null +++ b/saltpack/keybase_test.go @@ -0,0 +1,22 @@ +package saltpack_test + +import ( + "testing" + + "github.com/keys-pub/keys/saltpack" + "github.com/stretchr/testify/require" +) + +func TestKeybaseMessageNoKey(t *testing.T) { + msg := `BEGIN KEYBASE SALTPACK ENCRYPTED MESSAGE. kiS2n6W4XB3QNEC peK0YLJK3LobCmd gqRoOu9htbeNE4l cgh15YfdlKRoFob Gv3J1mr1FhUvKyU pm9W7ClSTRkJOX9 ig5OOn2RHKIpN20 ybTj8AzWbXBhmD8 y9fXvXmW3FMSnC7 Ara2CtZYt0gsE2o bTTsMhU9hBkTww9 rNTZErpLemI6vX0 ms3GBba8SVigyG9 SL4eGq8pzYJTYw7 U0eshvPZ3ikNfcV Z3wp9PRajDjkOMQ yMdj2NDXZDsBveA A0E1V3At27ZETJr OukyTS0hY4iVYXv qEbD5c80UENFJdl wvM152wLf7LwI4R NY9jkDsrXcaHrIJ I4UT6fkr2xTc0j4 DiMO7m5MNHZNc6q 99yLxq9KaRHhc8t D1k9DTKZWYIWrjc EJVErjMvjbBcoKu GOOPEdXwsHJ6q7W NkMrPVFZrQw8kvX Wop2vh1CZdMEEF7 k8Ekv8SBEosw5kQ G8iRPBp1fi491TZ R7Uf0YqtfBiZogG F3CO1tVWZAh3zVi XbnYtJIoTWCii1f tcbMPHlhlgX2NwW 7VAzUleQCWfikye 8KljVNitmKzmACy gGZMibJeKwo8x5h DuSXFDHJRGzFhEW smQz1U8GpHZ1bfC 4J7N8eQNameSAFG e95qC8eTHimQ6x7 ht5NzQC20VHH8mH 8qDd5uCbaGXPALp rerajB8P8AIuOrq hcy7WrNsIAXfQl5 Smm4EmP3JJgnurK UoYXeqbU2YsdzGZ 1kaVk4RpbOXPKps myeCMRlZhomDYDq MGimdSh41dCMEIz b2Yv4pbjSh4c7GD ESuHHoATzOWpjZu uQk4pjzr09HzbZo Vb3HlHqXyUdvd5E CjEPybUmdfuwaRV nSQSxKdvSORgKZq pOVswK9Y3J2aG9i l5Wmo7X22HMpak5 N2j3weYZYhnPqgX SFZAcuUSeDT5puW UFW3HxRRA08zMeZ . END KEYBASE SALTPACK ENCRYPTED MESSAGE.` + + kr := saltpack.NewKeyring() + _, _, enc, err := saltpack.Open([]byte(msg), kr) + require.Equal(t, saltpack.SigncryptEncoding, enc) + require.EqualError(t, err, "no decryption key found for message") + + msg2 := `BEGIN KEYBASE SALTPACK ENCRYPTED MESSAGE. kiPI2uHhOZmDhYo ynRuBAu5CSeHWTY sqCf8KAaFomjzNw j9M5xuCaxL97VRa nXAzIBiyO2gcv7V 4xKnLdJUiH1wYqd wzpflpZpHErQ9PD wnL0HoRq8LleQmr VY4TOtb9a6vMdIW wsRebbTQjYEvEmf mG2eiY0F9vA3WkN Eti2kNud2oFNjWC WzMhxgNEnb7xdX0 RUvXMNS7RhjWwmO pxo8z3zpcuPKslh 7QlWjinDuwLFAzJ z93mv8Fpoydj0LP 1bp4FcHhbqsBroE O7KskRL7QQ1y0nD cEuBcudG13G3woJ jMntM7zdAUejuQR 7PvGVoZnCXEqfvy X6F0rYpob9REIDs XW7fXqQlg13Pukw TeukcNcyshhksxR 4TgQqYwQ2s8Gert VMqKnSzucR2Nx0u WdG4oGKKLnWrBgU 7S47v8DcQwgLlEJ iMouf6gap48ovBQ rXuYbLnpjOe7UEM GIPmtLf58ettgRX SGx9mRwQlUkv1GU z6Wviuwx3syY2Dz 7BlCXKtbC0LgRpT 7g37GjMcCzAIxou yzocJ9x2M3aUN5s 6UnTZkZy3D7bITR q84XJh0qfd2MhjI ipASuygG3z8DtPB 1foWBXfS7ctXkph lqMQ0jV4zc6NBof XlTpx73ABTDvjkF q5hGHgJ6nK0JTAg 9ay6LoKBkWzkqph 77uQozls0t1TuZI l5mdZ7cjtLp48Ya ZwcE261wHlg5AUU 4HhGYqB7pTFI0qX xb8i1FepoQuWhlD 0leM1ezREZax4Xo jrSa6BToOwRAwMy U2dHKMQdAML812D 66vkdTJIWoDT61B z78xGEGL4fN5ijZ dxVNEulmP3GfSmS qhn2DpMSgdB9jYp OjNRl0Srq6YTSL. END KEYBASE SALTPACK ENCRYPTED MESSAGE.` + _, _, enc, err = saltpack.Open([]byte(msg2), kr) + require.Equal(t, saltpack.EncryptEncoding, enc) + require.EqualError(t, err, "no decryption key found for message") +} diff --git a/saltpack/signcrypt_examples_test.go b/saltpack/signcrypt_examples_test.go new file mode 100644 index 0000000..3a89dff --- /dev/null +++ b/saltpack/signcrypt_examples_test.go @@ -0,0 +1,58 @@ +package saltpack_test + +import ( + "fmt" + "log" + + "github.com/keys-pub/keys" + "github.com/keys-pub/keys/saltpack" +) + +func ExampleSigncrypt() { + alice := keys.NewEdX25519KeyFromSeed(testSeed(0x01)) + bobID := keys.ID("kex1syuhwr4g05t4744r23nvxnr7en9cmz53knhr0gja7c84hr7fkw2quf6zcg") + + message := []byte("hi bob") + + fmt.Printf("alice: %s\n", alice.ID()) + fmt.Printf("bob: %s\n", bobID) + + // Signcrypt from alice to bob + encrypted, err := saltpack.Signcrypt(message, true, alice, bobID) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s...\n", encrypted[0:30]) + // Output: + // alice: kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077 + // bob: kex1syuhwr4g05t4744r23nvxnr7en9cmz53knhr0gja7c84hr7fkw2quf6zcg + // BEGIN SALTPACK ENCRYPTED MESSA... +} + +func ExampleSigncryptOpen() { + aliceID := keys.ID("kex132yw8ht5p8cetl2jmvknewjawt9xwzdlrk2pyxlnwjyqrdq0dawqqph077") + encrypted := []byte(`BEGIN SALTPACK ENCRYPTED MESSAGE. + keDIDMQWYvVR58B FTfTeDQNHw4rtf4 DhnUhh7QIMs1BwB LmssBxGhQ4mlcCU qV8WjYl8IkxQJbg + ONicYJ6bKt4MtL5 u1uoXQQMHpGQoxv i81G0YjJmVk3fve kTnkT7hxuNZPhL3 2gdI2jzdhgOuv2I + GepiKbfYFkh9crE 1N4kuPgLFmiQoUb UxbqPeFjmNwUTf7 zGeNEy8DBW16Iyd jw64NZ1Ln4gebRP + 2mFMbPdyBRdxldx ugMs9cTZ2cTcyWJ mTPQ9RkdnnfPGdd k6x2hQWAdkwBOmy 4NcS7hFls2iGX4I + 4lh5nDtDzwGHFOn ehwbipT7iNVK9kE 388GznWBW4Vci88 43Z1Txd2cbm2dBJ y883ohi7SLL. + END SALTPACK ENCRYPTED MESSAGE.`) + + bob := keys.NewEdX25519KeyFromSeed(testSeed(0x02)) + + // Bob decrypts + out, sender, err := saltpack.SigncryptOpen(encrypted, true, saltpack.NewKeyring(bob)) + if err != nil { + log.Fatal(err) + } + + if sender != nil && sender.ID() == aliceID { + fmt.Printf("signer is alice\n") + } + fmt.Printf("%s\n", string(out)) + + // Output: + // signer is alice + // hi bob +}