You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2018/03/23 13:50:39 UTC

[12/25] brooklyn-client git commit: Add vendor file and remove glide from build/readme

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/openpgp/read_test.go
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/openpgp/read_test.go b/cli/vendor/golang.org/x/crypto/openpgp/read_test.go
new file mode 100644
index 0000000..7524a02
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/openpgp/read_test.go
@@ -0,0 +1,512 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+	"bytes"
+	_ "crypto/sha512"
+	"encoding/hex"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+
+	"golang.org/x/crypto/openpgp/errors"
+)
+
+func readerFromHex(s string) io.Reader {
+	data, err := hex.DecodeString(s)
+	if err != nil {
+		panic("readerFromHex: bad input")
+	}
+	return bytes.NewBuffer(data)
+}
+
+func TestReadKeyRing(t *testing.T) {
+	kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B {
+		t.Errorf("bad keyring: %#v", kring)
+	}
+}
+
+func TestRereadKeyRing(t *testing.T) {
+	kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	if err != nil {
+		t.Errorf("error in initial parse: %s", err)
+		return
+	}
+	out := new(bytes.Buffer)
+	err = kring[0].Serialize(out)
+	if err != nil {
+		t.Errorf("error in serialization: %s", err)
+		return
+	}
+	kring, err = ReadKeyRing(out)
+	if err != nil {
+		t.Errorf("error in second parse: %s", err)
+		return
+	}
+
+	if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+		t.Errorf("bad keyring: %#v", kring)
+	}
+}
+
+func TestReadPrivateKeyRing(t *testing.T) {
+	kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B || kring[0].PrimaryKey == nil {
+		t.Errorf("bad keyring: %#v", kring)
+	}
+}
+
+func TestReadDSAKey(t *testing.T) {
+	kring, err := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x0CCC0360 {
+		t.Errorf("bad parse: %#v", kring)
+	}
+}
+
+func TestDSAHashTruncatation(t *testing.T) {
+	// dsaKeyWithSHA512 was generated with GnuPG and --cert-digest-algo
+	// SHA512 in order to require DSA hash truncation to verify correctly.
+	_, err := ReadKeyRing(readerFromHex(dsaKeyWithSHA512))
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestGetKeyById(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+	keys := kring.KeysById(0xa34d7e18c20c31bb)
+	if len(keys) != 1 || keys[0].Entity != kring[0] {
+		t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+	}
+
+	keys = kring.KeysById(0xfd94408d4543314f)
+	if len(keys) != 1 || keys[0].Entity != kring[0] {
+		t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+	}
+}
+
+func checkSignedMessage(t *testing.T, signedHex, expected string) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+	md, err := ReadMessage(readerFromHex(signedHex), kring, nil, nil)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted {
+		t.Errorf("bad MessageDetails: %#v", md)
+	}
+
+	contents, err := ioutil.ReadAll(md.UnverifiedBody)
+	if err != nil {
+		t.Errorf("error reading UnverifiedBody: %s", err)
+	}
+	if string(contents) != expected {
+		t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+	}
+	if md.SignatureError != nil || md.Signature == nil {
+		t.Errorf("failed to validate: %s", md.SignatureError)
+	}
+}
+
+func TestSignedMessage(t *testing.T) {
+	checkSignedMessage(t, signedMessageHex, signedInput)
+}
+
+func TestTextSignedMessage(t *testing.T) {
+	checkSignedMessage(t, signedTextMessageHex, signedTextInput)
+}
+
+// The reader should detect "compressed quines", which are compressed
+// packets that expand into themselves and cause an infinite recursive
+// parsing loop.
+// The packet in this test case comes from Taylor R. Campbell at
+// http://mumble.net/~campbell/misc/pgp-quine/
+func TestCampbellQuine(t *testing.T) {
+	md, err := ReadMessage(readerFromHex(campbellQuine), nil, nil, nil)
+	if md != nil {
+		t.Errorf("Reading a compressed quine should not return any data: %#v", md)
+	}
+	structural, ok := err.(errors.StructuralError)
+	if !ok {
+		t.Fatalf("Unexpected class of error: %T", err)
+	}
+	if !strings.Contains(string(structural), "too many layers of packets") {
+		t.Fatalf("Unexpected error: %s", err)
+	}
+}
+
+var signedEncryptedMessageTests = []struct {
+	keyRingHex       string
+	messageHex       string
+	signedByKeyId    uint64
+	encryptedToKeyId uint64
+}{
+	{
+		testKeys1And2PrivateHex,
+		signedEncryptedMessageHex,
+		0xa34d7e18c20c31bb,
+		0x2a67d68660df41c7,
+	},
+	{
+		dsaElGamalTestKeysHex,
+		signedEncryptedMessage2Hex,
+		0x33af447ccd759b09,
+		0xcf6a7abcd43e3673,
+	},
+}
+
+func TestSignedEncryptedMessage(t *testing.T) {
+	for i, test := range signedEncryptedMessageTests {
+		expected := "Signed and encrypted message\n"
+		kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+		prompt := func(keys []Key, symmetric bool) ([]byte, error) {
+			if symmetric {
+				t.Errorf("prompt: message was marked as symmetrically encrypted")
+				return nil, errors.ErrKeyIncorrect
+			}
+
+			if len(keys) == 0 {
+				t.Error("prompt: no keys requested")
+				return nil, errors.ErrKeyIncorrect
+			}
+
+			err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+			if err != nil {
+				t.Errorf("prompt: error decrypting key: %s", err)
+				return nil, errors.ErrKeyIncorrect
+			}
+
+			return nil, nil
+		}
+
+		md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt, nil)
+		if err != nil {
+			t.Errorf("#%d: error reading message: %s", i, err)
+			return
+		}
+
+		if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+			t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+		}
+
+		contents, err := ioutil.ReadAll(md.UnverifiedBody)
+		if err != nil {
+			t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+		}
+		if string(contents) != expected {
+			t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+		}
+
+		if md.SignatureError != nil || md.Signature == nil {
+			t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+		}
+	}
+}
+
+func TestUnspecifiedRecipient(t *testing.T) {
+	expected := "Recipient unspecified\n"
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+
+	md, err := ReadMessage(readerFromHex(recipientUnspecifiedHex), kring, nil, nil)
+	if err != nil {
+		t.Errorf("error reading message: %s", err)
+		return
+	}
+
+	contents, err := ioutil.ReadAll(md.UnverifiedBody)
+	if err != nil {
+		t.Errorf("error reading UnverifiedBody: %s", err)
+	}
+	if string(contents) != expected {
+		t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+	}
+}
+
+func TestSymmetricallyEncrypted(t *testing.T) {
+	firstTimeCalled := true
+
+	prompt := func(keys []Key, symmetric bool) ([]byte, error) {
+		if len(keys) != 0 {
+			t.Errorf("prompt: len(keys) = %d (want 0)", len(keys))
+		}
+
+		if !symmetric {
+			t.Errorf("symmetric is not set")
+		}
+
+		if firstTimeCalled {
+			firstTimeCalled = false
+			return []byte("wrongpassword"), nil
+		}
+
+		return []byte("password"), nil
+	}
+
+	md, err := ReadMessage(readerFromHex(symmetricallyEncryptedCompressedHex), nil, prompt, nil)
+	if err != nil {
+		t.Errorf("ReadMessage: %s", err)
+		return
+	}
+
+	contents, err := ioutil.ReadAll(md.UnverifiedBody)
+	if err != nil {
+		t.Errorf("ReadAll: %s", err)
+	}
+
+	expectedCreationTime := uint32(1295992998)
+	if md.LiteralData.Time != expectedCreationTime {
+		t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
+	}
+
+	const expected = "Symmetrically encrypted.\n"
+	if string(contents) != expected {
+		t.Errorf("contents got: %s want: %s", string(contents), expected)
+	}
+}
+
+func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string, expectedSignerKeyId uint64) {
+	signed := bytes.NewBufferString(sigInput)
+	signer, err := CheckDetachedSignature(kring, signed, signature)
+	if err != nil {
+		t.Errorf("%s: signature error: %s", tag, err)
+		return
+	}
+	if signer == nil {
+		t.Errorf("%s: signer is nil", tag)
+		return
+	}
+	if signer.PrimaryKey.KeyId != expectedSignerKeyId {
+		t.Errorf("%s: wrong signer got:%x want:%x", tag, signer.PrimaryKey.KeyId, expectedSignerKeyId)
+	}
+}
+
+func TestDetachedSignature(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary", testKey1KeyId)
+	testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text", testKey1KeyId)
+	testDetachedSignature(t, kring, readerFromHex(detachedSignatureV3TextHex), signedInput, "v3", testKey1KeyId)
+
+	incorrectSignedInput := signedInput + "X"
+	_, err := CheckDetachedSignature(kring, bytes.NewBufferString(incorrectSignedInput), readerFromHex(detachedSignatureHex))
+	if err == nil {
+		t.Fatal("CheckDetachedSignature returned without error for bad signature")
+	}
+	if err == errors.ErrUnknownIssuer {
+		t.Fatal("CheckDetachedSignature returned ErrUnknownIssuer when the signer was known, but the signature invalid")
+	}
+}
+
+func TestDetachedSignatureDSA(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+	testDetachedSignature(t, kring, readerFromHex(detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+func TestMultipleSignaturePacketsDSA(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+	testDetachedSignature(t, kring, readerFromHex(missingHashFunctionHex+detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+func testHashFunctionError(t *testing.T, signatureHex string) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	_, err := CheckDetachedSignature(kring, nil, readerFromHex(signatureHex))
+	if err == nil {
+		t.Fatal("Packet with bad hash type was correctly parsed")
+	}
+	unsupported, ok := err.(errors.UnsupportedError)
+	if !ok {
+		t.Fatalf("Unexpected class of error: %s", err)
+	}
+	if !strings.Contains(string(unsupported), "hash ") {
+		t.Fatalf("Unexpected error: %s", err)
+	}
+}
+
+func TestUnknownHashFunction(t *testing.T) {
+	// unknownHashFunctionHex contains a signature packet with hash
+	// function type 153 (which isn't a real hash function id).
+	testHashFunctionError(t, unknownHashFunctionHex)
+}
+
+func TestMissingHashFunction(t *testing.T) {
+	// missingHashFunctionHex contains a signature packet that uses
+	// RIPEMD160, which isn't compiled in.  Since that's the only signature
+	// packet we don't find any suitable packets and end up with ErrUnknownIssuer
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+	_, err := CheckDetachedSignature(kring, nil, readerFromHex(missingHashFunctionHex))
+	if err == nil {
+		t.Fatal("Packet with missing hash type was correctly parsed")
+	}
+	if err != errors.ErrUnknownIssuer {
+		t.Fatalf("Unexpected class of error: %s", err)
+	}
+}
+
+func TestReadingArmoredPrivateKey(t *testing.T) {
+	el, err := ReadArmoredKeyRing(bytes.NewBufferString(armoredPrivateKeyBlock))
+	if err != nil {
+		t.Error(err)
+	}
+	if len(el) != 1 {
+		t.Errorf("got %d entities, wanted 1\n", len(el))
+	}
+}
+
+func TestReadingArmoredPublicKey(t *testing.T) {
+	el, err := ReadArmoredKeyRing(bytes.NewBufferString(e2ePublicKey))
+	if err != nil {
+		t.Error(err)
+	}
+	if len(el) != 1 {
+		t.Errorf("didn't get a valid entity")
+	}
+}
+
+func TestNoArmoredData(t *testing.T) {
+	_, err := ReadArmoredKeyRing(bytes.NewBufferString("foo"))
+	if _, ok := err.(errors.InvalidArgumentError); !ok {
+		t.Errorf("error was not an InvalidArgumentError: %s", err)
+	}
+}
+
+func testReadMessageError(t *testing.T, messageHex string) {
+	buf, err := hex.DecodeString(messageHex)
+	if err != nil {
+		t.Errorf("hex.DecodeString(): %v", err)
+	}
+
+	kr, err := ReadKeyRing(new(bytes.Buffer))
+	if err != nil {
+		t.Errorf("ReadKeyring(): %v", err)
+	}
+
+	_, err = ReadMessage(bytes.NewBuffer(buf), kr,
+		func([]Key, bool) ([]byte, error) {
+			return []byte("insecure"), nil
+		}, nil)
+
+	if err == nil {
+		t.Errorf("ReadMessage(): Unexpected nil error")
+	}
+}
+
+func TestIssue11503(t *testing.T) {
+	testReadMessageError(t, "8c040402000aa430aa8228b9248b01fc899a91197130303030")
+}
+
+func TestIssue11504(t *testing.T) {
+	testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130")
+}
+
+const testKey1KeyId = 0xA34D7E18C20C31BB
+const testKey3KeyId = 0x338934250CCC0360
+
+const signedInput = "Signed message\nline 2\nline 3\n"
+const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
+
+const recipientUnspecifiedHex = "848c0300000000000000000103ff62d4d578d03cf40c3da998dfe216c074fa6ddec5e31c197c9666ba292830d91d18716a80f699f9d897389a90e6d62d0238f5f07a5248073c0f24920e4bc4a30c2d17ee4e0cae7c3d4aaa4e8dced50e3010a80ee692175fa0385f62ecca4b56ee6e9980aa3ec51b61b077096ac9e800edaf161268593eedb6cc7027ff5cb32745d250010d407a6221ae22ef18469b444f2822478c4d190b24d36371a95cb40087cdd42d9399c3d06a53c0673349bfb607927f20d1e122bde1e2bf3aa6cae6edf489629bcaa0689539ae3b718914d88ededc3b"
+
+const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31bb167603ff57718d09f28a519fdc7b5a68b6a3336da04df85e38c5cd5d5bd2092fa4629848a33d85b1729402a2aab39c3ac19f9d573f773cc62c264dc924c067a79dfd8a863ae06c7c8686120760749f5fd9b1e03a64d20a7df3446ddc8f0aeadeaeba7cbaee5c1e366d65b6a0c6cc749bcb912d2f15013f812795c2e29eb7f7b77f39ce77"
+
+const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
+
+const detachedSignatureV3TextHex = "8900950305005255c25ca34d7e18c20c31bb0102bb3f04009f6589ef8a028d6e54f6eaf25432e590d31c3a41f4710897585e10c31e5e332c7f9f409af8512adceaff24d0da1474ab07aa7bce4f674610b010fccc5b579ae5eb00a127f272fb799f988ab8e4574c141da6dbfecfef7e6b2c478d9a3d2551ba741f260ee22bec762812f0053e05380bfdd55ad0f22d8cdf71b233fe51ae8a24"
+
+const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
+
+const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2a
 d484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626be
 b9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
+
+const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b4105465737420
 4b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c05756078
 5aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e1485
 6063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867
 e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d6
 6a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7
 ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af4
 47ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce9557
 6a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef558
 6cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
+const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
+
+const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
+
+const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
+const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
+
+const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a09103389
 34250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b0
 90807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const armoredPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
+idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
+vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
+AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
+0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
+IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
+VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
+gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
+TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
+q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
+dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
+ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
+eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
+AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
+bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
+/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
+A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
+TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
+lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
+rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
+oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
+QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
+nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
+AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
+BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
+AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
+VrM0m72/jnpKo04=
+=zNCn
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const e2ePublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+xv8AAABSBAAAAAATCCqGSM49AwEHAgME1LRoXSpOxtHXDUdmuvzchyg6005qIBJ4
+sfaSxX7QgH9RV2ONUhC+WiayCNADq+UMzuR/vunSr4aQffXvuGnR383/AAAAFDxk
+Z2lsQHlhaG9vLWluYy5jb20+wv8AAACGBBATCAA4/wAAAAWCVGvAG/8AAAACiwn/
+AAAACZC2VkQCOjdvYf8AAAAFlQgJCgv/AAAAA5YBAv8AAAACngEAAE1BAP0X8veD
+24IjmI5/C6ZAfVNXxgZZFhTAACFX75jUA3oD6AEAzoSwKf1aqH6oq62qhCN/pekX
++WAsVMBhNwzLpqtCRjLO/wAAAFYEAAAAABIIKoZIzj0DAQcCAwT50ain7vXiIRv8
+B1DO3x3cE/aattZ5sHNixJzRCXi2vQIA5QmOxZ6b5jjUekNbdHG3SZi1a2Ak5mfX
+fRxC/5VGAwEIB8L/AAAAZQQYEwgAGP8AAAAFglRrwBz/AAAACZC2VkQCOjdvYQAA
+FJAA9isX3xtGyMLYwp2F3nXm7QEdY5bq5VUcD/RJlj792VwA/1wH0pCzVLl4Q9F9
+ex7En5r7rHR5xwX82Msc+Rq9dSyO
+=7MrZ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const dsaKeyWithSHA512 = `9901a2044f04b07f110400db244efecc7316553ee08d179972aab87bb1214de7692593fcf5b6feb1c80fba268722dd464748539b85b81d574cd2d7ad0ca2444de4d849b8756bad7768c486c83a824f9bba4af773d11742bdfb4ac3b89ef8cc9452d4aad31a37e4b630d33927bff68e879284a1672659b8b298222fc68f370f3e24dccacc4a862442b9438b00a0ea444a24088dc23e26df7daf8f43cba3bffc4fe703fe3d6cd7fdca199d54ed8ae501c30e3ec7871ea9cdd4cf63cfe6fc82281d70a5b8bb493f922cd99fba5f088935596af087c8d818d5ec4d0b9afa7f070b3d7c1dd32a84fca08d8280b4890c8da1dde334de8e3cad8450eed2a4a4fcc2db7b8e5528b869a74a7f0189e11ef097ef1253582348de072bb07a9fa8ab838e993cef0ee203ff49298723e2d1f549b00559f886cd417a41692ce58d0ac1307dc71d85a8af21b0cf6eaa14baf2922d3a70389bedf17cc514ba0febbd107675a372fe84b90162a9e88b14d4b1c6be855b96b33fb198c46f058568817780435b6936167ebb3724b680f32bf27382ada2e37a879b3d9de2abe0c3f399350afd1ad438883f4791e2e3b4184453412068617368207472756e636174696f6e207465737488620413110a002205024f04b07f021b03060b090807030206150802090a0b0416020301021e0
 1021780000a0910ef20e0cefca131581318009e2bf3bf047a44d75a9bacd00161ee04d435522397009a03a60d51bd8a568c6c021c8d7cf1be8d990d6417b0020003`
+
+const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6acc0b21f32ffff010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
 10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000`

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go b/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go
new file mode 100644
index 0000000..0e8641e
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go
@@ -0,0 +1,273 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package s2k implements the various OpenPGP string-to-key transforms as
+// specified in RFC 4800 section 3.7.1.
+package s2k // import "golang.org/x/crypto/openpgp/s2k"
+
+import (
+	"crypto"
+	"hash"
+	"io"
+	"strconv"
+
+	"golang.org/x/crypto/openpgp/errors"
+)
+
+// Config collects configuration parameters for s2k key-stretching
+// transformatioms. A nil *Config is valid and results in all default
+// values. Currently, Config is used only by the Serialize function in
+// this package.
+type Config struct {
+	// Hash is the default hash function to be used. If
+	// nil, SHA1 is used.
+	Hash crypto.Hash
+	// S2KCount is only used for symmetric encryption. It
+	// determines the strength of the passphrase stretching when
+	// the said passphrase is hashed to produce a key. S2KCount
+	// should be between 1024 and 65011712, inclusive. If Config
+	// is nil or S2KCount is 0, the value 65536 used. Not all
+	// values in the above range can be represented. S2KCount will
+	// be rounded up to the next representable value if it cannot
+	// be encoded exactly. When set, it is strongly encrouraged to
+	// use a value that is at least 65536. See RFC 4880 Section
+	// 3.7.1.3.
+	S2KCount int
+}
+
+func (c *Config) hash() crypto.Hash {
+	if c == nil || uint(c.Hash) == 0 {
+		// SHA1 is the historical default in this package.
+		return crypto.SHA1
+	}
+
+	return c.Hash
+}
+
+func (c *Config) encodedCount() uint8 {
+	if c == nil || c.S2KCount == 0 {
+		return 96 // The common case. Correspoding to 65536
+	}
+
+	i := c.S2KCount
+	switch {
+	// Behave like GPG. Should we make 65536 the lowest value used?
+	case i < 1024:
+		i = 1024
+	case i > 65011712:
+		i = 65011712
+	}
+
+	return encodeCount(i)
+}
+
+// encodeCount converts an iterative "count" in the range 1024 to
+// 65011712, inclusive, to an encoded count. The return value is the
+// octet that is actually stored in the GPG file. encodeCount panics
+// if i is not in the above range (encodedCount above takes care to
+// pass i in the correct range). See RFC 4880 Section 3.7.7.1.
+func encodeCount(i int) uint8 {
+	if i < 1024 || i > 65011712 {
+		panic("count arg i outside the required range")
+	}
+
+	for encoded := 0; encoded < 256; encoded++ {
+		count := decodeCount(uint8(encoded))
+		if count >= i {
+			return uint8(encoded)
+		}
+	}
+
+	return 255
+}
+
+// decodeCount returns the s2k mode 3 iterative "count" corresponding to
+// the encoded octet c.
+func decodeCount(c uint8) int {
+	return (16 + int(c&15)) << (uint32(c>>4) + 6)
+}
+
+// Simple writes to out the result of computing the Simple S2K function (RFC
+// 4880, section 3.7.1.1) using the given hash and input passphrase.
+func Simple(out []byte, h hash.Hash, in []byte) {
+	Salted(out, h, in, nil)
+}
+
+var zero [1]byte
+
+// Salted writes to out the result of computing the Salted S2K function (RFC
+// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
+func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
+	done := 0
+	var digest []byte
+
+	for i := 0; done < len(out); i++ {
+		h.Reset()
+		for j := 0; j < i; j++ {
+			h.Write(zero[:])
+		}
+		h.Write(salt)
+		h.Write(in)
+		digest = h.Sum(digest[:0])
+		n := copy(out[done:], digest)
+		done += n
+	}
+}
+
+// Iterated writes to out the result of computing the Iterated and Salted S2K
+// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
+// salt and iteration count.
+func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
+	combined := make([]byte, len(in)+len(salt))
+	copy(combined, salt)
+	copy(combined[len(salt):], in)
+
+	if count < len(combined) {
+		count = len(combined)
+	}
+
+	done := 0
+	var digest []byte
+	for i := 0; done < len(out); i++ {
+		h.Reset()
+		for j := 0; j < i; j++ {
+			h.Write(zero[:])
+		}
+		written := 0
+		for written < count {
+			if written+len(combined) > count {
+				todo := count - written
+				h.Write(combined[:todo])
+				written = count
+			} else {
+				h.Write(combined)
+				written += len(combined)
+			}
+		}
+		digest = h.Sum(digest[:0])
+		n := copy(out[done:], digest)
+		done += n
+	}
+}
+
+// Parse reads a binary specification for a string-to-key transformation from r
+// and returns a function which performs that transform.
+func Parse(r io.Reader) (f func(out, in []byte), err error) {
+	var buf [9]byte
+
+	_, err = io.ReadFull(r, buf[:2])
+	if err != nil {
+		return
+	}
+
+	hash, ok := HashIdToHash(buf[1])
+	if !ok {
+		return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
+	}
+	if !hash.Available() {
+		return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
+	}
+	h := hash.New()
+
+	switch buf[0] {
+	case 0:
+		f := func(out, in []byte) {
+			Simple(out, h, in)
+		}
+		return f, nil
+	case 1:
+		_, err = io.ReadFull(r, buf[:8])
+		if err != nil {
+			return
+		}
+		f := func(out, in []byte) {
+			Salted(out, h, in, buf[:8])
+		}
+		return f, nil
+	case 3:
+		_, err = io.ReadFull(r, buf[:9])
+		if err != nil {
+			return
+		}
+		count := decodeCount(buf[8])
+		f := func(out, in []byte) {
+			Iterated(out, h, in, buf[:8], count)
+		}
+		return f, nil
+	}
+
+	return nil, errors.UnsupportedError("S2K function")
+}
+
+// Serialize salts and stretches the given passphrase and writes the
+// resulting key into key. It also serializes an S2K descriptor to
+// w. The key stretching can be configured with c, which may be
+// nil. In that case, sensible defaults will be used.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
+	var buf [11]byte
+	buf[0] = 3 /* iterated and salted */
+	buf[1], _ = HashToHashId(c.hash())
+	salt := buf[2:10]
+	if _, err := io.ReadFull(rand, salt); err != nil {
+		return err
+	}
+	encodedCount := c.encodedCount()
+	count := decodeCount(encodedCount)
+	buf[10] = encodedCount
+	if _, err := w.Write(buf[:]); err != nil {
+		return err
+	}
+
+	Iterated(key, c.hash().New(), passphrase, salt, count)
+	return nil
+}
+
+// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
+// Go's crypto.Hash type. See RFC 4880, section 9.4.
+var hashToHashIdMapping = []struct {
+	id   byte
+	hash crypto.Hash
+	name string
+}{
+	{1, crypto.MD5, "MD5"},
+	{2, crypto.SHA1, "SHA1"},
+	{3, crypto.RIPEMD160, "RIPEMD160"},
+	{8, crypto.SHA256, "SHA256"},
+	{9, crypto.SHA384, "SHA384"},
+	{10, crypto.SHA512, "SHA512"},
+	{11, crypto.SHA224, "SHA224"},
+}
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+	for _, m := range hashToHashIdMapping {
+		if m.id == id {
+			return m.hash, true
+		}
+	}
+	return 0, false
+}
+
+// HashIdToString returns the name of the hash function corresponding to the
+// given OpenPGP hash id, or panics if id is unknown.
+func HashIdToString(id byte) (name string, ok bool) {
+	for _, m := range hashToHashIdMapping {
+		if m.id == id {
+			return m.name, true
+		}
+	}
+
+	return "", false
+}
+
+// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+	for _, m := range hashToHashIdMapping {
+		if m.hash == h {
+			return m.id, true
+		}
+	}
+	return 0, false
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go b/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go
new file mode 100644
index 0000000..183d260
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go
@@ -0,0 +1,137 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2k
+
+import (
+	"bytes"
+	"crypto"
+	_ "crypto/md5"
+	"crypto/rand"
+	"crypto/sha1"
+	_ "crypto/sha256"
+	_ "crypto/sha512"
+	"encoding/hex"
+	"testing"
+
+	_ "golang.org/x/crypto/ripemd160"
+)
+
+var saltedTests = []struct {
+	in, out string
+}{
+	{"hello", "10295ac1"},
+	{"world", "ac587a5e"},
+	{"foo", "4dda8077"},
+	{"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
+	{"x", "f1d3f289"},
+	{"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
+}
+
+func TestSalted(t *testing.T) {
+	h := sha1.New()
+	salt := [4]byte{1, 2, 3, 4}
+
+	for i, test := range saltedTests {
+		expected, _ := hex.DecodeString(test.out)
+		out := make([]byte, len(expected))
+		Salted(out, h, []byte(test.in), salt[:])
+		if !bytes.Equal(expected, out) {
+			t.Errorf("#%d, got: %x want: %x", i, out, expected)
+		}
+	}
+}
+
+var iteratedTests = []struct {
+	in, out string
+}{
+	{"hello", "83126105"},
+	{"world", "6fa317f9"},
+	{"foo", "8fbc35b9"},
+	{"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
+	{"x", "5a684dfe"},
+	{"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
+}
+
+func TestIterated(t *testing.T) {
+	h := sha1.New()
+	salt := [4]byte{4, 3, 2, 1}
+
+	for i, test := range iteratedTests {
+		expected, _ := hex.DecodeString(test.out)
+		out := make([]byte, len(expected))
+		Iterated(out, h, []byte(test.in), salt[:], 31)
+		if !bytes.Equal(expected, out) {
+			t.Errorf("#%d, got: %x want: %x", i, out, expected)
+		}
+	}
+}
+
+var parseTests = []struct {
+	spec, in, out string
+}{
+	/* Simple with SHA1 */
+	{"0002", "hello", "aaf4c61d"},
+	/* Salted with SHA1 */
+	{"01020102030405060708", "hello", "f4f7d67e"},
+	/* Iterated with SHA1 */
+	{"03020102030405060708f1", "hello", "f2a57b7c"},
+}
+
+func TestParse(t *testing.T) {
+	for i, test := range parseTests {
+		spec, _ := hex.DecodeString(test.spec)
+		buf := bytes.NewBuffer(spec)
+		f, err := Parse(buf)
+		if err != nil {
+			t.Errorf("%d: Parse returned error: %s", i, err)
+			continue
+		}
+
+		expected, _ := hex.DecodeString(test.out)
+		out := make([]byte, len(expected))
+		f(out, []byte(test.in))
+		if !bytes.Equal(out, expected) {
+			t.Errorf("%d: output got: %x want: %x", i, out, expected)
+		}
+		if testing.Short() {
+			break
+		}
+	}
+}
+
+func TestSerialize(t *testing.T) {
+	hashes := []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.RIPEMD160,
+		crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224}
+	testCounts := []int{-1, 0, 1024, 65536, 4063232, 65011712}
+	for _, h := range hashes {
+		for _, c := range testCounts {
+			testSerializeConfig(t, &Config{Hash: h, S2KCount: c})
+		}
+	}
+}
+
+func testSerializeConfig(t *testing.T, c *Config) {
+	t.Logf("Running testSerializeConfig() with config: %+v", c)
+
+	buf := bytes.NewBuffer(nil)
+	key := make([]byte, 16)
+	passphrase := []byte("testing")
+	err := Serialize(buf, key, rand.Reader, passphrase, c)
+	if err != nil {
+		t.Errorf("failed to serialize: %s", err)
+		return
+	}
+
+	f, err := Parse(buf)
+	if err != nil {
+		t.Errorf("failed to reparse: %s", err)
+		return
+	}
+	key2 := make([]byte, len(key))
+	f(key2, passphrase)
+	if !bytes.Equal(key2, key) {
+		t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
+	}
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/openpgp/write.go
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/openpgp/write.go b/cli/vendor/golang.org/x/crypto/openpgp/write.go
new file mode 100644
index 0000000..15aaa1a
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/openpgp/write.go
@@ -0,0 +1,378 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+	"crypto"
+	"hash"
+	"io"
+	"strconv"
+	"time"
+
+	"golang.org/x/crypto/openpgp/armor"
+	"golang.org/x/crypto/openpgp/errors"
+	"golang.org/x/crypto/openpgp/packet"
+	"golang.org/x/crypto/openpgp/s2k"
+)
+
+// DetachSign signs message with the private key from signer (which must
+// already have been decrypted) and writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+	return detachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// ArmoredDetachSign signs message with the private key from signer (which
+// must already have been decrypted) and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
+	return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// DetachSignText signs message (after canonicalising the line endings) with
+// the private key from signer (which must already have been decrypted) and
+// writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+	return detachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+// ArmoredDetachSignText signs message (after canonicalising the line endings)
+// with the private key from signer (which must already have been decrypted)
+// and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+	return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+	out, err := armor.Encode(w, SignatureType, nil)
+	if err != nil {
+		return
+	}
+	err = detachSign(out, signer, message, sigType, config)
+	if err != nil {
+		return
+	}
+	return out.Close()
+}
+
+func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+	if signer.PrivateKey == nil {
+		return errors.InvalidArgumentError("signing key doesn't have a private key")
+	}
+	if signer.PrivateKey.Encrypted {
+		return errors.InvalidArgumentError("signing key is encrypted")
+	}
+
+	sig := new(packet.Signature)
+	sig.SigType = sigType
+	sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
+	sig.Hash = config.Hash()
+	sig.CreationTime = config.Now()
+	sig.IssuerKeyId = &signer.PrivateKey.KeyId
+
+	h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
+	if err != nil {
+		return
+	}
+	io.Copy(wrappedHash, message)
+
+	err = sig.Sign(h, signer.PrivateKey, config)
+	if err != nil {
+		return
+	}
+
+	return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+	// IsBinary can be set to hint that the contents are binary data.
+	IsBinary bool
+	// FileName hints at the name of the file that should be written. It's
+	// truncated to 255 bytes if longer. It may be empty to suggest that the
+	// file should not be written to disk. It may be equal to "_CONSOLE" to
+	// suggest the data should not be written to disk.
+	FileName string
+	// ModTime contains the modification time of the file, or the zero time if not applicable.
+	ModTime time.Time
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+// If config is nil, sensible defaults will be used.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+	if hints == nil {
+		hints = &FileHints{}
+	}
+
+	key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
+	if err != nil {
+		return
+	}
+	w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
+	if err != nil {
+		return
+	}
+
+	literaldata := w
+	if algo := config.Compression(); algo != packet.CompressionNone {
+		var compConfig *packet.CompressionConfig
+		if config != nil {
+			compConfig = config.CompressionConfig
+		}
+		literaldata, err = packet.SerializeCompressed(w, algo, compConfig)
+		if err != nil {
+			return
+		}
+	}
+
+	var epochSeconds uint32
+	if !hints.ModTime.IsZero() {
+		epochSeconds = uint32(hints.ModTime.Unix())
+	}
+	return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds)
+}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+	var j int
+	for _, v := range a {
+		for _, v2 := range b {
+			if v == v2 {
+				a[j] = v
+				j++
+				break
+			}
+		}
+	}
+
+	return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+	v, ok := s2k.HashToHashId(h)
+	if !ok {
+		panic("tried to convert unknown hash")
+	}
+	return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+	var signer *packet.PrivateKey
+	if signed != nil {
+		signKey, ok := signed.signingKey(config.Now())
+		if !ok {
+			return nil, errors.InvalidArgumentError("no valid signing keys")
+		}
+		signer = signKey.PrivateKey
+		if signer == nil {
+			return nil, errors.InvalidArgumentError("no private key in signing key")
+		}
+		if signer.Encrypted {
+			return nil, errors.InvalidArgumentError("signing key must be decrypted")
+		}
+	}
+
+	// These are the possible ciphers that we'll use for the message.
+	candidateCiphers := []uint8{
+		uint8(packet.CipherAES128),
+		uint8(packet.CipherAES256),
+		uint8(packet.CipherCAST5),
+	}
+	// These are the possible hash functions that we'll use for the signature.
+	candidateHashes := []uint8{
+		hashToHashId(crypto.SHA256),
+		hashToHashId(crypto.SHA512),
+		hashToHashId(crypto.SHA1),
+		hashToHashId(crypto.RIPEMD160),
+	}
+	// In the event that a recipient doesn't specify any supported ciphers
+	// or hash functions, these are the ones that we assume that every
+	// implementation supports.
+	defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+	defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+	encryptKeys := make([]Key, len(to))
+	for i := range to {
+		var ok bool
+		encryptKeys[i], ok = to[i].encryptionKey(config.Now())
+		if !ok {
+			return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+		}
+
+		sig := to[i].primaryIdentity().SelfSignature
+
+		preferredSymmetric := sig.PreferredSymmetric
+		if len(preferredSymmetric) == 0 {
+			preferredSymmetric = defaultCiphers
+		}
+		preferredHashes := sig.PreferredHash
+		if len(preferredHashes) == 0 {
+			preferredHashes = defaultHashes
+		}
+		candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+		candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+	}
+
+	if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+		return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+	}
+
+	cipher := packet.CipherFunction(candidateCiphers[0])
+	// If the cipher specifed by config is a candidate, we'll use that.
+	configuredCipher := config.Cipher()
+	for _, c := range candidateCiphers {
+		cipherFunc := packet.CipherFunction(c)
+		if cipherFunc == configuredCipher {
+			cipher = cipherFunc
+			break
+		}
+	}
+
+	var hash crypto.Hash
+	for _, hashId := range candidateHashes {
+		if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
+			hash = h
+			break
+		}
+	}
+
+	// If the hash specified by config is a candidate, we'll use that.
+	if configuredHash := config.Hash(); configuredHash.Available() {
+		for _, hashId := range candidateHashes {
+			if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
+				hash = h
+				break
+			}
+		}
+	}
+
+	if hash == 0 {
+		hashId := candidateHashes[0]
+		name, ok := s2k.HashIdToString(hashId)
+		if !ok {
+			name = "#" + strconv.Itoa(int(hashId))
+		}
+		return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
+	}
+
+	symKey := make([]byte, cipher.KeySize())
+	if _, err := io.ReadFull(config.Random(), symKey); err != nil {
+		return nil, err
+	}
+
+	for _, key := range encryptKeys {
+		if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil {
+			return nil, err
+		}
+	}
+
+	encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config)
+	if err != nil {
+		return
+	}
+
+	if signer != nil {
+		ops := &packet.OnePassSignature{
+			SigType:    packet.SigTypeBinary,
+			Hash:       hash,
+			PubKeyAlgo: signer.PubKeyAlgo,
+			KeyId:      signer.KeyId,
+			IsLast:     true,
+		}
+		if err := ops.Serialize(encryptedData); err != nil {
+			return nil, err
+		}
+	}
+
+	if hints == nil {
+		hints = &FileHints{}
+	}
+
+	w := encryptedData
+	if signer != nil {
+		// If we need to write a signature packet after the literal
+		// data then we need to stop literalData from closing
+		// encryptedData.
+		w = noOpCloser{encryptedData}
+
+	}
+	var epochSeconds uint32
+	if !hints.ModTime.IsZero() {
+		epochSeconds = uint32(hints.ModTime.Unix())
+	}
+	literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
+	if err != nil {
+		return nil, err
+	}
+
+	if signer != nil {
+		return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil
+	}
+	return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+	encryptedData io.WriteCloser
+	literalData   io.WriteCloser
+	hashType      crypto.Hash
+	h             hash.Hash
+	signer        *packet.PrivateKey
+	config        *packet.Config
+}
+
+func (s signatureWriter) Write(data []byte) (int, error) {
+	s.h.Write(data)
+	return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() error {
+	sig := &packet.Signature{
+		SigType:      packet.SigTypeBinary,
+		PubKeyAlgo:   s.signer.PubKeyAlgo,
+		Hash:         s.hashType,
+		CreationTime: s.config.Now(),
+		IssuerKeyId:  &s.signer.KeyId,
+	}
+
+	if err := sig.Sign(s.h, s.signer, s.config); err != nil {
+		return err
+	}
+	if err := s.literalData.Close(); err != nil {
+		return err
+	}
+	if err := sig.Serialize(s.encryptedData); err != nil {
+		return err
+	}
+	return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+	w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err error) {
+	return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() error {
+	return nil
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/openpgp/write_test.go
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/openpgp/write_test.go b/cli/vendor/golang.org/x/crypto/openpgp/write_test.go
new file mode 100644
index 0000000..8e9a335
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/openpgp/write_test.go
@@ -0,0 +1,259 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+	"bytes"
+	"io"
+	"io/ioutil"
+	"testing"
+	"time"
+
+	"golang.org/x/crypto/openpgp/packet"
+)
+
+func TestSignDetached(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+	out := bytes.NewBuffer(nil)
+	message := bytes.NewBufferString(signedInput)
+	err := DetachSign(out, kring[0], message, nil)
+	if err != nil {
+		t.Error(err)
+	}
+
+	testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignTextDetached(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+	out := bytes.NewBuffer(nil)
+	message := bytes.NewBufferString(signedInput)
+	err := DetachSignText(out, kring[0], message, nil)
+	if err != nil {
+		t.Error(err)
+	}
+
+	testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignDetachedDSA(t *testing.T) {
+	kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
+	out := bytes.NewBuffer(nil)
+	message := bytes.NewBufferString(signedInput)
+	err := DetachSign(out, kring[0], message, nil)
+	if err != nil {
+		t.Error(err)
+	}
+
+	testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
+}
+
+func TestNewEntity(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	// Check bit-length with no config.
+	e, err := NewEntity("Test User", "test", "test@example.com", nil)
+	if err != nil {
+		t.Errorf("failed to create entity: %s", err)
+		return
+	}
+	bl, err := e.PrimaryKey.BitLength()
+	if err != nil {
+		t.Errorf("failed to find bit length: %s", err)
+	}
+	if int(bl) != defaultRSAKeyBits {
+		t.Errorf("BitLength %v, expected %v", defaultRSAKeyBits)
+	}
+
+	// Check bit-length with a config.
+	cfg := &packet.Config{RSABits: 1024}
+	e, err = NewEntity("Test User", "test", "test@example.com", cfg)
+	if err != nil {
+		t.Errorf("failed to create entity: %s", err)
+		return
+	}
+	bl, err = e.PrimaryKey.BitLength()
+	if err != nil {
+		t.Errorf("failed to find bit length: %s", err)
+	}
+	if int(bl) != cfg.RSABits {
+		t.Errorf("BitLength %v, expected %v", bl, cfg.RSABits)
+	}
+
+	w := bytes.NewBuffer(nil)
+	if err := e.SerializePrivate(w, nil); err != nil {
+		t.Errorf("failed to serialize entity: %s", err)
+		return
+	}
+	serialized := w.Bytes()
+
+	el, err := ReadKeyRing(w)
+	if err != nil {
+		t.Errorf("failed to reparse entity: %s", err)
+		return
+	}
+
+	if len(el) != 1 {
+		t.Errorf("wrong number of entities found, got %d, want 1", len(el))
+	}
+
+	w = bytes.NewBuffer(nil)
+	if err := e.SerializePrivate(w, nil); err != nil {
+		t.Errorf("failed to serialize entity second time: %s", err)
+		return
+	}
+
+	if !bytes.Equal(w.Bytes(), serialized) {
+		t.Errorf("results differed")
+	}
+}
+
+func TestSymmetricEncryption(t *testing.T) {
+	buf := new(bytes.Buffer)
+	plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil, nil)
+	if err != nil {
+		t.Errorf("error writing headers: %s", err)
+		return
+	}
+	message := []byte("hello world\n")
+	_, err = plaintext.Write(message)
+	if err != nil {
+		t.Errorf("error writing to plaintext writer: %s", err)
+	}
+	err = plaintext.Close()
+	if err != nil {
+		t.Errorf("error closing plaintext writer: %s", err)
+	}
+
+	md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, error) {
+		return []byte("testing"), nil
+	}, nil)
+	if err != nil {
+		t.Errorf("error rereading message: %s", err)
+	}
+	messageBuf := bytes.NewBuffer(nil)
+	_, err = io.Copy(messageBuf, md.UnverifiedBody)
+	if err != nil {
+		t.Errorf("error rereading message: %s", err)
+	}
+	if !bytes.Equal(message, messageBuf.Bytes()) {
+		t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
+	}
+}
+
+var testEncryptionTests = []struct {
+	keyRingHex string
+	isSigned   bool
+}{
+	{
+		testKeys1And2PrivateHex,
+		false,
+	},
+	{
+		testKeys1And2PrivateHex,
+		true,
+	},
+	{
+		dsaElGamalTestKeysHex,
+		false,
+	},
+	{
+		dsaElGamalTestKeysHex,
+		true,
+	},
+}
+
+func TestEncryption(t *testing.T) {
+	for i, test := range testEncryptionTests {
+		kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+		passphrase := []byte("passphrase")
+		for _, entity := range kring {
+			if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+				err := entity.PrivateKey.Decrypt(passphrase)
+				if err != nil {
+					t.Errorf("#%d: failed to decrypt key", i)
+				}
+			}
+			for _, subkey := range entity.Subkeys {
+				if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+					err := subkey.PrivateKey.Decrypt(passphrase)
+					if err != nil {
+						t.Errorf("#%d: failed to decrypt subkey", i)
+					}
+				}
+			}
+		}
+
+		var signed *Entity
+		if test.isSigned {
+			signed = kring[0]
+		}
+
+		buf := new(bytes.Buffer)
+		w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */, nil)
+		if err != nil {
+			t.Errorf("#%d: error in Encrypt: %s", i, err)
+			continue
+		}
+
+		const message = "testing"
+		_, err = w.Write([]byte(message))
+		if err != nil {
+			t.Errorf("#%d: error writing plaintext: %s", i, err)
+			continue
+		}
+		err = w.Close()
+		if err != nil {
+			t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+			continue
+		}
+
+		md, err := ReadMessage(buf, kring, nil /* no prompt */, nil)
+		if err != nil {
+			t.Errorf("#%d: error reading message: %s", i, err)
+			continue
+		}
+
+		testTime, _ := time.Parse("2006-01-02", "2013-07-01")
+		if test.isSigned {
+			signKey, _ := kring[0].signingKey(testTime)
+			expectedKeyId := signKey.PublicKey.KeyId
+			if md.SignedByKeyId != expectedKeyId {
+				t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+			}
+			if md.SignedBy == nil {
+				t.Errorf("#%d: failed to find the signing Entity", i)
+			}
+		}
+
+		plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+		if err != nil {
+			t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+			continue
+		}
+
+		encryptKey, _ := kring[0].encryptionKey(testTime)
+		expectedKeyId := encryptKey.PublicKey.KeyId
+		if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+			t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+		}
+
+		if string(plaintext) != message {
+			t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+		}
+
+		if test.isSigned {
+			if md.SignatureError != nil {
+				t.Errorf("#%d: signature error: %s", i, md.SignatureError)
+			}
+			if md.Signature == nil {
+				t.Error("signature missing")
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-client/blob/799e9ccb/cli/vendor/golang.org/x/crypto/otr/libotr_test_helper.c
----------------------------------------------------------------------
diff --git a/cli/vendor/golang.org/x/crypto/otr/libotr_test_helper.c b/cli/vendor/golang.org/x/crypto/otr/libotr_test_helper.c
new file mode 100644
index 0000000..b3ca072
--- /dev/null
+++ b/cli/vendor/golang.org/x/crypto/otr/libotr_test_helper.c
@@ -0,0 +1,197 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code can be compiled and used to test the otr package against libotr.
+// See otr_test.go.
+
+// +build ignore
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <proto.h>
+#include <message.h>
+#include <privkey.h>
+
+static int g_session_established = 0;
+
+OtrlPolicy policy(void *opdata, ConnContext *context) {
+  return OTRL_POLICY_ALWAYS;
+}
+
+int is_logged_in(void *opdata, const char *accountname, const char *protocol,
+                 const char *recipient) {
+  return 1;
+}
+
+void inject_message(void *opdata, const char *accountname, const char *protocol,
+                    const char *recipient, const char *message) {
+  printf("%s\n", message);
+  fflush(stdout);
+  fprintf(stderr, "libotr helper sent: %s\n", message);
+}
+
+void update_context_list(void *opdata) {}
+
+void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
+                     const char *protocol, const char *username,
+                     unsigned char fingerprint[20]) {
+  fprintf(stderr, "NEW FINGERPRINT\n");
+  g_session_established = 1;
+}
+
+void write_fingerprints(void *opdata) {}
+
+void gone_secure(void *opdata, ConnContext *context) {}
+
+void gone_insecure(void *opdata, ConnContext *context) {}
+
+void still_secure(void *opdata, ConnContext *context, int is_reply) {}
+
+int max_message_size(void *opdata, ConnContext *context) { return 99999; }
+
+const char *account_name(void *opdata, const char *account,
+                         const char *protocol) {
+  return "ACCOUNT";
+}
+
+void account_name_free(void *opdata, const char *account_name) {}
+
+const char *error_message(void *opdata, ConnContext *context,
+                          OtrlErrorCode err_code) {
+  return "ERR";
+}
+
+void error_message_free(void *opdata, const char *msg) {}
+
+void resent_msg_prefix_free(void *opdata, const char *prefix) {}
+
+void handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
+                      ConnContext *context, unsigned short progress_event,
+                      char *question) {}
+
+void handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
+                      ConnContext *context, const char *message,
+                      gcry_error_t err) {
+  fprintf(stderr, "msg event: %d %s\n", msg_event, message);
+}
+
+OtrlMessageAppOps uiops = {
+    policy,
+    NULL,
+    is_logged_in,
+    inject_message,
+    update_context_list,
+    new_fingerprint,
+    write_fingerprints,
+    gone_secure,
+    gone_insecure,
+    still_secure,
+    max_message_size,
+    account_name,
+    account_name_free,
+    NULL, /* received_symkey */
+    error_message,
+    error_message_free,
+    NULL, /* resent_msg_prefix */
+    resent_msg_prefix_free,
+    handle_smp_event,
+    handle_msg_event,
+    NULL /* create_instag */,
+    NULL /* convert_msg */,
+    NULL /* convert_free */,
+    NULL /* timer_control */,
+};
+
+static const char kPrivateKeyData[] =
+    "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa "
+    "(p "
+    "#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F"
+    "30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E"
+    "5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB"
+    "8C031D3561FECEE72EBB4A090D450A9B7A857#) (q "
+    "#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g "
+    "#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F"
+    "1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F"
+    "6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57"
+    "597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y "
+    "#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF"
+    "2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93"
+    "454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A"
+    "3C0FF501E3DC673B76D7BABF349009B6ECF#) (x "
+    "#14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
+
+int main() {
+  OTRL_INIT;
+
+  // We have to write the private key information to a file because the libotr
+  // API demands a filename to read from.
+  const char *tmpdir = "/tmp";
+  if (getenv("TMP")) {
+    tmpdir = getenv("TMP");
+  }
+
+  char private_key_file[256];
+  snprintf(private_key_file, sizeof(private_key_file),
+           "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
+  int fd = mkstemp(private_key_file);
+  if (fd == -1) {
+    perror("creating temp file");
+  }
+  write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1);
+  close(fd);
+
+  OtrlUserState userstate = otrl_userstate_create();
+  otrl_privkey_read(userstate, private_key_file);
+  unlink(private_key_file);
+
+  fprintf(stderr, "libotr helper started\n");
+
+  char buf[4096];
+
+  for (;;) {
+    char *message = fgets(buf, sizeof(buf), stdin);
+    if (strlen(message) == 0) {
+      break;
+    }
+    message[strlen(message) - 1] = 0;
+    fprintf(stderr, "libotr helper got: %s\n", message);
+
+    char *newmessage = NULL;
+    OtrlTLV *tlvs;
+    int ignore_message = otrl_message_receiving(
+        userstate, &uiops, NULL, "account", "proto", "peer", message,
+        &newmessage, &tlvs, NULL, NULL, NULL);
+    if (tlvs) {
+      otrl_tlv_free(tlvs);
+    }
+
+    if (newmessage != NULL) {
+      fprintf(stderr, "libotr got: %s\n", newmessage);
+      otrl_message_free(newmessage);
+
+      gcry_error_t err;
+      char *newmessage = NULL;
+
+      err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto",
+                                 "peer", 0, "test message", NULL, &newmessage,
+                                 OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL);
+      if (newmessage == NULL) {
+        fprintf(stderr, "libotr didn't encrypt message\n");
+        return 1;
+      }
+      write(1, newmessage, strlen(newmessage));
+      write(1, "\n", 1);
+      fprintf(stderr, "libotr sent: %s\n", newmessage);
+      otrl_message_free(newmessage);
+
+      g_session_established = 0;
+      write(1, "?OTRv2?\n", 8);
+      fprintf(stderr, "libotr sent: ?OTRv2\n");
+    }
+  }
+
+  return 0;
+}