uncommitted - golang-github-twstrike-otr3

Ready changes

Summary

Import uploads missing from VCS:

Diff

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 845ca06..0000000
--- a/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-.pc
diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644
index 0000000..6857a8d
--- /dev/null
+++ b/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644
index 0000000..c206706
--- /dev/null
+++ b/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/.pc/applied-patches b/.pc/applied-patches
new file mode 100644
index 0000000..8cfcc44
--- /dev/null
+++ b/.pc/applied-patches
@@ -0,0 +1,2 @@
+test_location.patch
+go-1.11.patch
diff --git a/.pc/go-1.11.patch/ake.go b/.pc/go-1.11.patch/ake.go
new file mode 100644
index 0000000..ec8c367
--- /dev/null
+++ b/.pc/go-1.11.patch/ake.go
@@ -0,0 +1,389 @@
+package otr3
+
+import (
+	"crypto/hmac"
+	"crypto/subtle"
+	"io"
+	"math/big"
+	"time"
+)
+
+type ake struct {
+	secretExponent   *big.Int
+	ourPublicValue   *big.Int
+	theirPublicValue *big.Int
+
+	// TODO: why this number here?
+	r [16]byte
+
+	encryptedGx []byte
+
+	// SIZE: this should always be version.hash2Length
+	xhashedGx []byte
+
+	revealKey akeKeys
+	sigKey    akeKeys
+
+	state authState
+	keys  keyManagementContext
+
+	lastStateChange time.Time
+}
+
+func (c *Conversation) ensureAKE() {
+	if c.ake != nil {
+		return
+	}
+
+	c.initAKE()
+}
+
+func (c *Conversation) initAKE() {
+	c.ake = &ake{
+		state: authStateNone{},
+	}
+}
+
+func (c *Conversation) calcAKEKeys(s *big.Int) {
+	c.ssid, c.ake.revealKey, c.ake.sigKey = calculateAKEKeys(s, c.version)
+}
+
+func (c *Conversation) setSecretExponent(val *big.Int) {
+	c.ake.secretExponent = new(big.Int).Set(val)
+	c.ake.ourPublicValue = modExp(g1, val)
+}
+
+func (c *Conversation) calcDHSharedSecret() *big.Int {
+	return modExp(c.ake.theirPublicValue, c.ake.secretExponent)
+}
+
+func (c *Conversation) generateEncryptedSignature(key *akeKeys) ([]byte, error) {
+	verifyData := appendAll(c.ake.ourPublicValue, c.ake.theirPublicValue, c.ourCurrentKey.PublicKey(), c.ake.keys.ourKeyID)
+
+	mb := sumHMAC(key.m1, verifyData, c.version)
+	xb, err := c.calcXb(key, mb)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return appendData(nil, xb), nil
+}
+func appendAll(one, two *big.Int, publicKey PublicKey, keyID uint32) []byte {
+	return appendWord(append(appendMPI(appendMPI(nil, one), two), publicKey.serialize()...), keyID)
+}
+
+func fixedSize(s int, v []byte) []byte {
+	if len(v) < s {
+		vv := make([]byte, s)
+		copy(vv, v)
+		return vv
+	}
+	return v
+}
+
+func (c *Conversation) calcXb(key *akeKeys, mb []byte) ([]byte, error) {
+	xb := c.ourCurrentKey.PublicKey().serialize()
+	xb = appendWord(xb, c.ake.keys.ourKeyID)
+
+	sigb, err := c.ourCurrentKey.Sign(c.rand(), mb)
+	if err == io.ErrUnexpectedEOF {
+		return nil, errShortRandomRead
+	}
+
+	if err != nil {
+		return nil, err
+	}
+
+	// this error can't happen, since key.c is fixed to the correct size
+	xb, _ = encrypt(fixedSize(c.version.keyLength(), key.c), append(xb, sigb...))
+
+	return xb, nil
+}
+
+// dhCommitMessage = bob = x
+// Bob ---- DH Commit -----------> Alice
+func (c *Conversation) dhCommitMessage() ([]byte, error) {
+	c.initAKE()
+	c.ake.keys.ourKeyID = 0
+
+	// TODO: where does this 40 come from?
+	x, err := c.randMPI(make([]byte, 40))
+	if err != nil {
+		return nil, err
+	}
+
+	c.setSecretExponent(x)
+	wipeBigInt(x)
+
+	if err := c.randomInto(c.ake.r[:]); err != nil {
+		return nil, err
+	}
+
+	// this can't return an error, since ake.r is of a fixed size that is always correct
+	c.ake.encryptedGx, _ = encrypt(c.ake.r[:], appendMPI(nil, c.ake.ourPublicValue))
+
+	return c.serializeDHCommit(c.ake.ourPublicValue), nil
+}
+
+func (c *Conversation) serializeDHCommit(public *big.Int) []byte {
+	dhCommitMsg := dhCommit{
+		encryptedGx: c.ake.encryptedGx,
+		yhashedGx:   c.version.hash2(appendMPI(nil, public)),
+	}
+	return dhCommitMsg.serialize()
+}
+
+// dhKeyMessage = alice = y
+// Alice -- DH Key --------------> Bob
+func (c *Conversation) dhKeyMessage() ([]byte, error) {
+	c.initAKE()
+
+	// TODO: where does this 40 come from?
+	y, err := c.randMPI(make([]byte, 40)[:])
+
+	if err != nil {
+		return nil, err
+	}
+
+	c.setSecretExponent(y)
+	wipeBigInt(y)
+
+	return c.serializeDHKey(), nil
+}
+
+func (c *Conversation) serializeDHKey() []byte {
+	dhKeyMsg := dhKey{
+		gy: c.ake.ourPublicValue,
+	}
+
+	return dhKeyMsg.serialize()
+}
+
+// revealSigMessage = bob = x
+// Bob ---- Reveal Signature ----> Alice
+func (c *Conversation) revealSigMessage() ([]byte, error) {
+	c.calcAKEKeys(c.calcDHSharedSecret())
+	c.ake.keys.ourKeyID++
+
+	encryptedSig, err := c.generateEncryptedSignature(&c.ake.revealKey)
+	if err != nil {
+		return nil, err
+	}
+
+	macSig := sumHMAC(c.ake.revealKey.m2, encryptedSig, c.version)
+	revealSigMsg := revealSig{
+		r:            c.ake.r,
+		encryptedSig: encryptedSig,
+		macSig:       macSig,
+	}
+
+	return revealSigMsg.serialize(c.version), nil
+}
+
+// sigMessage = alice = y
+// Alice -- Signature -----------> Bob
+func (c *Conversation) sigMessage() ([]byte, error) {
+	c.ake.keys.ourKeyID++
+
+	encryptedSig, err := c.generateEncryptedSignature(&c.ake.sigKey)
+	if err != nil {
+		return nil, err
+	}
+
+	macSig := sumHMAC(c.ake.sigKey.m2, encryptedSig, c.version)
+	sigMsg := sig{
+		encryptedSig: encryptedSig,
+		macSig:       macSig,
+	}
+
+	return sigMsg.serialize(c.version), nil
+}
+
+// processDHCommit = alice = y
+// Bob ---- DH Commit -----------> Alice
+func (c *Conversation) processDHCommit(msg []byte) error {
+	dhCommitMsg := dhCommit{}
+	err := dhCommitMsg.deserialize(msg)
+	if err != nil {
+		return err
+	}
+
+	c.ake.encryptedGx = dhCommitMsg.encryptedGx
+	c.ake.xhashedGx = dhCommitMsg.yhashedGx
+
+	return err
+}
+
+// processDHKey = bob = x
+// Alice -- DH Key --------------> Bob
+func (c *Conversation) processDHKey(msg []byte) (isSame bool, err error) {
+	dhKeyMsg := dhKey{}
+	err = dhKeyMsg.deserialize(msg)
+	if err != nil {
+		return false, err
+	}
+
+	if !isGroupElement(dhKeyMsg.gy) {
+		return false, newOtrError("DH value out of range")
+	}
+
+	//If receive same public key twice, just retransmit the previous Reveal Signature
+	if c.ake.theirPublicValue != nil {
+		isSame = eq(c.ake.theirPublicValue, dhKeyMsg.gy)
+		return
+	}
+
+	c.ake.theirPublicValue = dhKeyMsg.gy
+	return
+}
+
+// processRevealSig = alice = y
+// Bob ---- Reveal Signature ----> Alice
+func (c *Conversation) processRevealSig(msg []byte) (err error) {
+	revealSigMsg := revealSig{}
+	err = revealSigMsg.deserialize(msg, c.version)
+	if err != nil {
+		return
+	}
+
+	r := revealSigMsg.r[:]
+	theirMAC := revealSigMsg.macSig
+	encryptedSig := revealSigMsg.encryptedSig
+
+	decryptedGx := make([]byte, len(c.ake.encryptedGx))
+	if err = decrypt(r, decryptedGx, c.ake.encryptedGx); err != nil {
+		return
+	}
+
+	if err = checkDecryptedGx(decryptedGx, c.ake.xhashedGx, c.version); err != nil {
+		return
+	}
+
+	if c.ake.theirPublicValue, err = extractGx(decryptedGx); err != nil {
+		return
+	}
+
+	c.calcAKEKeys(c.calcDHSharedSecret())
+	if err = c.processEncryptedSig(encryptedSig, theirMAC, &c.ake.revealKey); err != nil {
+		return newOtrError("in reveal signature message: " + err.Error())
+	}
+
+	return nil
+}
+
+// processSig = bob = x
+// Alice -- Signature -----------> Bob
+func (c *Conversation) processSig(msg []byte) (err error) {
+	sigMsg := sig{}
+	err = sigMsg.deserialize(msg)
+	if err != nil {
+		return
+	}
+
+	theirMAC := sigMsg.macSig
+	encryptedSig := sigMsg.encryptedSig
+
+	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.ake.sigKey); err != nil {
+		return newOtrError("in signature message: " + err.Error())
+	}
+
+	return nil
+}
+
+func (c *Conversation) checkedSignatureVerification(mb, sig []byte) error {
+	rest, ok := c.theirKey.Verify(mb, sig)
+	if !ok {
+		return newOtrError("bad signature in encrypted signature")
+	}
+
+	if len(rest) > 0 {
+		return errCorruptEncryptedSignature
+	}
+
+	return nil
+}
+
+func verifyEncryptedSignatureMAC(encryptedSig []byte, theirMAC []byte, keys *akeKeys, v otrVersion) error {
+	tomac := appendData(nil, encryptedSig)
+
+	myMAC := sumHMAC(keys.m2, tomac, v)[:v.truncateLength()]
+
+	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
+		return newOtrError("bad signature MAC in encrypted signature")
+	}
+
+	return nil
+}
+
+func (c *Conversation) parseTheirKey(key []byte) (sig []byte, keyID uint32, err error) {
+	var rest []byte
+	var ok1 bool
+	rest, ok1, c.theirKey = ParsePublicKey(key)
+	sig, keyID, ok2 := extractWord(rest)
+
+	if !ok1 || !ok2 {
+		return nil, 0, errCorruptEncryptedSignature
+	}
+
+	return
+}
+
+func (c *Conversation) expectedMessageHMAC(keyID uint32, keys *akeKeys) []byte {
+	verifyData := appendAll(c.ake.theirPublicValue, c.ake.ourPublicValue, c.theirKey, keyID)
+	return sumHMAC(keys.m1, verifyData, c.version)
+}
+
+func (c *Conversation) processEncryptedSig(encryptedSig []byte, theirMAC []byte, keys *akeKeys) error {
+	if err := verifyEncryptedSignatureMAC(encryptedSig, theirMAC, keys, c.version); err != nil {
+		return err
+	}
+
+	decryptedSig := encryptedSig
+	if err := decrypt(fixedSize(c.version.keyLength(), keys.c), decryptedSig, encryptedSig); err != nil {
+		return err
+	}
+
+	sig, keyID, err := c.parseTheirKey(decryptedSig)
+	if err != nil {
+		return err
+	}
+
+	mb := c.expectedMessageHMAC(keyID, keys)
+	if err := c.checkedSignatureVerification(mb, sig); err != nil {
+		return err
+	}
+
+	c.ake.keys.theirKeyID = keyID
+
+	return nil
+}
+
+func extractGx(decryptedGx []byte) (*big.Int, error) {
+	newData, gx, ok := extractMPI(decryptedGx)
+	if !ok || len(newData) > 0 {
+		return gx, newOtrError("gx corrupt after decryption")
+	}
+
+	if !isGroupElement(gx) {
+		return gx, newOtrError("DH value out of range")
+	}
+
+	return gx, nil
+}
+
+func sumHMAC(key, data []byte, v otrVersion) []byte {
+	mac := hmac.New(v.hash2Instance, key)
+	mac.Write(data)
+	return mac.Sum(nil)
+}
+
+func checkDecryptedGx(decryptedGx, hashedGx []byte, v otrVersion) error {
+	digest := v.hash2(decryptedGx)
+
+	if subtle.ConstantTimeCompare(digest[:], hashedGx[:]) == 0 {
+		return newOtrError("bad commit MAC in reveal signature message")
+	}
+
+	return nil
+}
diff --git a/.pc/go-1.11.patch/ake_test.go b/.pc/go-1.11.patch/ake_test.go
new file mode 100644
index 0000000..b16bc2f
--- /dev/null
+++ b/.pc/go-1.11.patch/ake_test.go
@@ -0,0 +1,506 @@
+package otr3
+
+import (
+	"encoding/hex"
+	"io"
+	"math/big"
+	"testing"
+)
+
+var (
+	fixedr               = bytesFromHex("abcdabcdabcdabcdabcdabcdabcdabcd")
+	expectedSharedSecret = bnFromHex("b15e9eb80f16f4beabcf7ac44c06f0b69b9f890a86a11b6cc2fd29e0f7cd15d9af7c052c4c55dfce929783e339ef094eedcfcaeb9edf896b7e201d46f16ba42dbec0a9738daa37c47a598849735b8b9ac8c98578431f8c7a6a54944ec6d830cb0ffcdf31d39cb8414bd3ddae0c483daf4e80a5990f7618edf648e68935126639d1752f49b2b8a83b170f39dd7d2a2c4ab99cb28684df2c6ee1feff9d171c25059eb6920bdf4cdab2fc0aed4aafeb66a51e938db8ca80881ad219413ecf7e0257")
+	expectedC            = bytesFromHex("d942cc80b66503414c05e3752d9ba5c4")
+	expectedM1           = bytesFromHex("b6254b8eab0ad98152949454d23c8c9b08e4e9cf423b27edc09b1975a76eb59c")
+	expectedM2           = bytesFromHex("954be27015eeb0455250144d906e83e7d329c49581aea634c4189a3c981184f5")
+	alicePrivateKey      = parseIntoPrivateKey("000000000080c81c2cb2eb729b7e6fd48e975a932c638b3a9055478583afa46755683e30102447f6da2d8bec9f386bbb5da6403b0040fee8650b6ab2d7f32c55ab017ae9b6aec8c324ab5844784e9a80e194830d548fb7f09a0410df2c4d5c8bc2b3e9ad484e65412be689cf0834694e0839fb2954021521ffdffb8f5c32c14dbf2020b3ce7500000014da4591d58def96de61aea7b04a8405fe1609308d000000808ddd5cb0b9d66956e3dea5a915d9aba9d8a6e7053b74dadb2fc52f9fe4e5bcc487d2305485ed95fed026ad93f06ebb8c9e8baf693b7887132c7ffdd3b0f72f4002ff4ed56583ca7c54458f8c068ca3e8a4dfa309d1dd5d34e2a4b68e6f4338835e5e0fb4317c9e4c7e4806dafda3ef459cd563775a586dd91b1319f72621bf3f00000080b8147e74d8c45e6318c37731b8b33b984a795b3653c2cd1d65cc99efe097cb7eb2fa49569bab5aab6e8a1c261a27d0f7840a5e80b317e6683042b59b6dceca2879c6ffc877a465be690c15e4a42f9a7588e79b10faac11b1ce3741fcef7aba8ce05327a2c16d279ee1b3d77eb783fb10e3356caa25635331e26dd42b8396c4d00000001420bec691fea37ecea58a5c717142f0b804452f57")
+	bobPrivateKey        = parseIntoPrivateKey("000000000080a5138eb3d3eb9c1d85716faecadb718f87d31aaed1157671d7fee7e488f95e8e0ba60ad449ec732710a7dec5190f7182af2e2f98312d98497221dff160fd68033dd4f3a33b7c078d0d9f66e26847e76ca7447d4bab35486045090572863d9e4454777f24d6706f63e02548dfec2d0a620af37bbc1d24f884708a212c343b480d00000014e9c58f0ea21a5e4dfd9f44b6a9f7f6a9961a8fa9000000803c4d111aebd62d3c50c2889d420a32cdf1e98b70affcc1fcf44d59cca2eb019f6b774ef88153fb9b9615441a5fe25ea2d11b74ce922ca0232bd81b3c0fcac2a95b20cb6e6c0c5c1ace2e26f65dc43c751af0edbb10d669890e8ab6beea91410b8b2187af1a8347627a06ecea7e0f772c28aae9461301e83884860c9b656c722f0000008065af8625a555ea0e008cd04743671a3cda21162e83af045725db2eb2bb52712708dc0cc1a84c08b3649b88a966974bde27d8612c2861792ec9f08786a246fcadd6d8d3a81a32287745f309238f47618c2bd7612cb8b02d940571e0f30b96420bcd462ff542901b46109b1e5ad6423744448d20a57818a8cbb1647d0fea3b664e0000001440f9f2eb554cb00d45a5826b54bfa419b6980e48")
+)
+
+func Test_dhCommitMessage(t *testing.T) {
+	rnd := fixedRand([]string{hex.EncodeToString(fixedX().Bytes()), hex.EncodeToString(fixedr[:])})
+	c := newConversation(otrV3{}, rnd)
+
+	c.ourCurrentKey = bobPrivateKey
+
+	var out []byte
+	out = appendData(out, encryptedFixedGX())
+	out = appendData(out, hashedFixedGX())
+
+	result, err := c.dhCommitMessage()
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, result, out)
+}
+
+func Test_dhKeyMessage(t *testing.T) {
+	rnd := fixedRand([]string{hex.EncodeToString(fixedX().Bytes()), hex.EncodeToString(fixedr[:])})
+	c := newConversation(otrV3{}, rnd)
+
+	c.ourCurrentKey = alicePrivateKey
+	expectedGyValue := bnFromHex("075dfab5a1eab059052d0ad881c4938d52669630d61833a367155d67d03a457f619683d0fa829781e974fd24f6865e8128a9312a167b77326a87dea032fc31784d05b18b9cbafebe162ae9b5369f8b0c5911cf1be757f45f2a674be5126a714a6366c28086b3c7088911dcc4e5fb1481ad70a5237b8e4a6aff4954c2ca6df338b9f08691e4c0defe12689b37d4df30ddef2687f789fcf623c5d0cf6f09b7e5e69f481d5fd1b24a77636fb676e6d733d129eb93e81189340233044766a36eb07d")
+
+	var out []byte
+	out = appendMPI(out, expectedGyValue)
+
+	result, err := c.dhKeyMessage()
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, result, out)
+}
+
+func Test_dhKeyMessage_returnsAnErrorIfTheresNotEnoughRandomnessForAnMPI(t *testing.T) {
+	rnd := fixedRand([]string{"0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A"})
+	c := newConversation(otrV3{}, rnd)
+	_, err := c.dhKeyMessage()
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_revealSigMessage(t *testing.T) {
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	c := newConversation(otrV3{}, rnd)
+
+	c.ourCurrentKey = bobPrivateKey
+	c.initAKE()
+	copy(c.ake.r[:], fixedr)
+	c.setSecretExponent(fixedX())
+	c.ake.theirPublicValue = fixedGY()
+	expectedEncryptedSignature := bytesFromHex("000001d2dda2d4ef365711c172dad92804b201fcd2fdd6444568ebf0844019fb65ca4f5f57031936f9a339e08bfd4410905ab86c5d6f73e6c94de6a207f373beff3f7676faee7b1d3be21e630fe42e95db9d4ac559252bff530481301b590e2163b99bde8aa1b07448bf7252588e317b0ba2fc52f85a72a921ba757785b949e5e682341d98800aa180aa0bd01f51180d48260e4358ffae72a97f652f02eb6ae3bc6a25a317d0ca5ed0164a992240baac8e043f848332d22c10a46d12c745dc7b1b0ee37fd14614d4b69d500b8ce562040e3a4bfdd1074e2312d3e3e4c68bd15d70166855d8141f695b21c98c6055a5edb9a233925cf492218342450b806e58b3a821e5d1d2b9c6b9cbcba263908d7190a3428ace92572c064a328f86fa5b8ad2a9c76d5b9dcaeae5327f545b973795f7c655248141c2f82db0a2045e95c1936b726d6474f50283289e92ab5c7297081a54b9e70fce87603506dedd6734bab3c1567ee483cd4bcb0e669d9d97866ca274f178841dafc2acfdcd10cb0e2d07db244ff4b1d23afe253831f142083d912a7164a3425f82c95675298cf3c5eb3e096bbc95e44ecffafbb585738723c0adbe11f16c311a6cddde630b9c304717ce5b09247d482f32709ea71ced16ba930a554f9949c1acbecf")
+	expedctedMACSignature := bytesFromHex("8e6e5ef63a4e8d6aa2cfb1c5fe1831498862f69d7de32af4f9895180e4b494e6")
+
+	var out []byte
+	out = appendData(out, c.ake.r[:])
+	out = append(out, expectedEncryptedSignature...)
+	out = append(out, expedctedMACSignature[:20]...)
+
+	result, err := c.revealSigMessage()
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, result, out)
+}
+
+func Test_revealSigMessage_increasesOurKeyId(t *testing.T) {
+	var ourKeyID uint32 = 1
+	c := newConversation(otrV3{}, fixtureRand())
+	c.ourCurrentKey = bobPrivateKey
+	c.initAKE()
+	c.setSecretExponent(fixedX())
+	c.ake.theirPublicValue = fixedGY()
+	c.ake.keys.ourKeyID = ourKeyID
+
+	_, err := c.revealSigMessage()
+	assertEquals(t, err, nil)
+	assertEquals(t, c.ake.keys.ourKeyID, ourKeyID+1)
+}
+
+func Test_processDHKey(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	c.initAKE()
+	c.ake.theirPublicValue = fixedGY()
+
+	msg := appendMPI(nil, c.ake.theirPublicValue)
+
+	isSame, err := c.processDHKey(msg)
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, isSame, true)
+}
+
+func Test_processDHKeyNotSame(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	c.initAKE()
+	c.ake.theirPublicValue = fixedGY()
+
+	msg := appendMPI(nil, fixedGX())
+
+	isSame, err := c.processDHKey(msg)
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, isSame, false)
+}
+
+func Test_processDHKeyHavingError(t *testing.T) {
+	invalidGy := bnFromHex("751234566dfab5a1eab059052d0ad881c4938d52669630d61833a367155d67d03a457f619683d0fa829781e974fd24f6865e8128a9312a167b77326a87dea032fc31784d05b18b9cbafebe162ae9b5369f8b0c5911cf1be757f45f2a674be5126a714a6366c28086b3c7088911dcc4e5fb1481ad70a5237b8e4a6aff4954c2ca6df338b9f08691e4c0defe12689b37d4df30ddef2687f789fcf623c5d0cf6f09b7e5e69f481d5fd1b24a77636fb676e6d733d129eb93e81189340233044766a36eb07d")
+
+	c := newConversation(otrV2{}, fixtureRand())
+	c.initAKE()
+	c.ake.theirPublicValue = fixedGY()
+
+	msg := appendMPI(nil, invalidGy)
+
+	isSame, err := c.processDHKey(msg)
+	assertEquals(t, err.Error(), "otr: DH value out of range")
+	assertDeepEquals(t, isSame, false)
+}
+
+func Test_processEncryptedSig(t *testing.T) {
+	rnd := fixedRand([]string{})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+	c.ake.keys.ourKeyID = 1
+	c.calcAKEKeys(c.calcDHSharedSecret())
+
+	_, encryptedSig, _ := extractData(bytesFromHex("000001d2dda2d4ef365711c172dad92804b201fcd2fdd6444568ebf0844019fb65ca4f5f57031936f9a339e08bfd4410905ab86c5d6f73e6c94de6a207f373beff3f7676faee7b1d3be21e630fe42e95db9d4ac559252bff530481301b590e2163b99bde8aa1b07448bf7252588e317b0ba2fc52f85a72a921ba757785b949e5e682341d98800aa180aa0bd01f51180d48260e4358ffae72a97f652f02eb6ae3bc6a25a317d0ca5ed0164a992240baac8e043f848332d22c10a46d12c745dc7b1b0ee37fd14614d4b69d500b8ce562040e3a4bfdd1074e2312d3e3e4c68bd15d70166855d8141f695b21c98c6055a5edb9a233925cf492218342450b806e58b3a821e5d1d2b9c6b9cbcba263908d7190a3428ace92572c064a328f86fa5b8ad2a9c76d5b9dcaeae5327f545b973795f7c655248141c2f82db0a2045e95c1936b726d6474f50283289e92ab5c7297081a54b9e70fce87603506dedd6734bab3c1567ee483cd4bcb0e669d9d97866ca274f178841dafc2acfdcd10cb0e2d07db244ff4b1d23afe253831f142083d912a7164a3425f82c95675298cf3c5eb3e096bbc95e44ecffafbb585738723c0adbe11f16c311a6cddde630b9c304717ce5b09247d482f32709ea71ced16ba930a554f9949c1acbecf"))
+	macSignature := bytesFromHex("8e6e5ef63a4e8d6aa2cfb1c5fe1831498862f69d7de32af4f9895180e4b494e6")
+	err := c.processEncryptedSig(encryptedSig, macSignature[:20], &c.ake.revealKey)
+	assertEquals(t, err, nil)
+	assertEquals(t, c.ake.keys.theirKeyID, uint32(1))
+}
+
+func Test_processEncryptedSigWithBadSignatureMACError(t *testing.T) {
+	c := Conversation{version: otrV3{}}
+	c.initAKE()
+
+	_, encryptedSig, _ := extractData(bytesFromHex("000001b2dda2d4ef365711c172dad92804b201fcd2fdd6444568ebf0844019fb65ca4f5f57031936f9a339e08bfd4410905ab86c5d6f73e6c94de6a207f373beff3f7676faee7b1d3be21e630fe42e95db9d4ac559252bff530481301b590e2163b99bde8aa1b07448bf7252588e317b0ba2fc52f85a72a921ba757785b949e5e682341d98800aa180aa0bd01f51180d48260e4358ffae72a97f652f02eb6ae3bc6a25a317d0ca5ed0164a992240baac8e043f848332d22c10a46d12c745dc7b1b0ee37fd14614d4b69d500b8ce562040e3a4bfdd1074e2312d3e3e4c68bd15d70166855d8141f695b21c98c6055a5edb9a233925cf492218342450b806e58b3a821e5d1d2b9c6b9cbcba263908d7190a3428ace92572c064a328f86fa5b8ad2a9c76d5b9dcaeae5327f545b973795f7c655248141c2f82db0a2045e95c1936b726d6474f50283289e92ab5c7297081a54b9e70fce87603506dedd6734bab3c1567ee483cd4bcb0e669d9d97866ca274f178841dafc2acfdcd10cb0e2d07db244ff4b1d23afe253831f142083d912a7164a3425f82c95675298cf3c5eb3e096bbc95e44ecffafbb585738723c0adbe11f16c311a6cddde630b9c304717ce5b09247d482f32709ea71ced16ba930a554f9949c1acbecf"))
+	macSignature := bytesFromHex("8e6e5ef63a4e8d6aa2cfb1c5fe1831498862f69d7de32af4f9895180e4b494e6")
+	err := c.processEncryptedSig(encryptedSig, macSignature[:20], &c.ake.revealKey)
+	assertEquals(t, err.Error(), "otr: bad signature MAC in encrypted signature")
+	assertEquals(t, c.ake.keys.theirKeyID, uint32(0))
+}
+
+func Test_processEncryptedSigWithBadSignatureError(t *testing.T) {
+	rnd := fixedRand([]string{})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+	c.ourCurrentKey = bobPrivateKey
+	c.theirKey = bobPrivateKey.PublicKey()
+	c.setSecretExponent(fixedX())
+	c.ake.theirPublicValue = fixedGY()
+	c.ake.keys.ourKeyID = 1
+	s := c.calcDHSharedSecret()
+	c.calcAKEKeys(s)
+
+	_, encryptedSig, _ := extractData(bytesFromHex("000001d2dda2d4ef365711c172dad92804b201fcd2fdd6444568ebf0844019fb65ca4f5f57031936f9a339e08bfd4410905ab86c5d6f73e6c94de6a207f373beff3f7676faee7b1d3be21e630fe42e95db9d4ac559252bff530481301b590e2163b99bde8aa1b07448bf7252588e317b0ba2fc52f85a72a921ba757785b949e5e682341d98800aa180aa0bd01f51180d48260e4358ffae72a97f652f02eb6ae3bc6a25a317d0ca5ed0164a992240baac8e043f848332d22c10a46d12c745dc7b1b0ee37fd14614d4b69d500b8ce562040e3a4bfdd1074e2312d3e3e4c68bd15d70166855d8141f695b21c98c6055a5edb9a233925cf492218342450b806e58b3a821e5d1d2b9c6b9cbcba263908d7190a3428ace92572c064a328f86fa5b8ad2a9c76d5b9dcaeae5327f545b973795f7c655248141c2f82db0a2045e95c1936b726d6474f50283289e92ab5c7297081a54b9e70fce87603506dedd6734bab3c1567ee483cd4bcb0e669d9d97866ca274f178841dafc2acfdcd10cb0e2d07db244ff4b1d23afe253831f142083d912a7164a3425f82c95675298cf3c5eb3e096bbc95e44ecffafbb585738723c0adbe11f16c311a6cddde630b9c304717ce5b09247d482f32709ea71ced16ba930a554f9949c1acbeca"))
+	macSignature := bytesFromHex("741f14776485e6c593928fd859afe1ab4896f1e6")
+	err := c.processEncryptedSig(encryptedSig, macSignature[:20], &c.ake.revealKey)
+	assertEquals(t, err.Error(), "otr: bad signature in encrypted signature")
+	assertEquals(t, c.ake.keys.theirKeyID, uint32(0))
+}
+
+func Test_processRevealSig(t *testing.T) {
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	bob := newConversation(otrV3{}, rnd)
+	bob.initAKE()
+	alice := newConversation(otrV3{}, rnd)
+	alice.initAKE()
+
+	bob.ourCurrentKey = bobPrivateKey
+	copy(bob.ake.r[:], fixedr)
+	bob.setSecretExponent(fixedX())
+	bob.ake.theirPublicValue = fixedGY()
+	msg, err := bob.revealSigMessage()
+
+	alice.setSecretExponent(fixedY())
+	alice.ake.encryptedGx = bytesFromHex("5dd6a5999be73a99b80bdb78194a125f3067bd79e69c648b76a068117a8c4d0f36f275305423a933541937145d85ab4618094cbafbe4db0c0081614c1ff0f516c3dc4f352e9c92f88e4883166f12324d82240a8f32874c3d6bc35acedb8d501aa0111937a4859f33aa9b43ec342d78c3a45a5939c1e58e6b4f02725c1922f3df8754d1e1ab7648f558e9043ad118e63603b3ba2d8cbfea99a481835e42e73e6cd6019840f4470b606e168b1cd4a1f401c3dc52525d79fa6b959a80d4e11f1ec3a7984cf9")
+	alice.ake.xhashedGx = bytesFromHex("a3f2c4b9e3a7d1f565157ae7b0e71c721d59d3c79d39e5e4e8d08cb8464ff857")
+	err = alice.processRevealSig(msg)
+
+	assertEquals(t, err, nil)
+	assertEquals(t, alice.ake.keys.theirKeyID, uint32(1))
+	assertEquals(t, bob.ake.keys.ourKeyID, uint32(1))
+}
+
+func Test_processSig(t *testing.T) {
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	alice := newConversation(otrV3{}, rnd)
+	alice.initAKE()
+	alice.ourCurrentKey = bobPrivateKey
+	alice.setSecretExponent(fixedY())
+	alice.ake.theirPublicValue = fixedGX()
+	msg, _ := alice.sigMessage()
+
+	bob := newConversation(otrV3{}, rnd)
+	bob.initAKE()
+	bob.ake.sigKey = alice.ake.sigKey
+	bob.ourCurrentKey = alicePrivateKey
+	bob.setSecretExponent(fixedX())
+	bob.ake.theirPublicValue = fixedGY()
+
+	err := bob.processSig(msg)
+
+	assertEquals(t, err, nil)
+	assertEquals(t, alice.ake.keys.ourKeyID, uint32(1))
+	assertEquals(t, bob.ake.keys.theirKeyID, uint32(1))
+}
+
+func Test_processSig_returnsErrorIfTheSignatureDataIsInvalid(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	err := c.processSig([]byte{0x01, 0x01, 0x00})
+	assertDeepEquals(t, err, newOtrError("corrupt signature message"))
+}
+func Test_processRevealSig_returnsErrorIfTheRDataIsInvalid(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	err := c.processRevealSig([]byte{0x01, 0x01, 0x00})
+	assertDeepEquals(t, err, newOtrError("corrupt reveal signature message"))
+}
+
+func Test_processRevealSig_returnsErrorIfTheSignatureDataIsInvalid(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	err := c.processRevealSig([]byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01})
+	assertDeepEquals(t, err, newOtrError("corrupt reveal signature message"))
+}
+
+func Test_sigMessage(t *testing.T) {
+	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = alicePrivateKey
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+
+	expectedEncryptedSignature, _ := hex.DecodeString("000001d2b4f6ac650cc1d28f61a3b9bdf3cd60e2d1ea55d4c56e9f954eb22e10764861fb40d69917f5c4249fa701f3c04fae9449cd13a5054861f95fbc5775fc3cfd931cf5cc1a89eac82e7209b607c4fbf18df945e23bd0e91365fcc6c5dac072703dd8e2287372107f6a2cbb9139f5e82108d4cbcc1c6cdfcc772014136e756338745e2210d42c6e3ec4e9cf87fa8ebd8190e00f3a54bec86ee06cb7664059bb0fa79529e9d2e563ffecc5561477b3ba6bbf4ac679624b6da69a85822ed5c6ceb56a98740b1002026c503c39badab13b5d5ec948bbb961f0c90e68894a1fb70645a8e21ffe6b78e2e4ee62a62c48bd54e3d27c1166d098791518b53a10c409b5e55d16555b721a7750b7084e8972540bf0f1d76602e9b5fd58f94ed2dbf69fafccef84fdca2f9d800346b2358a200db060d8cf1b984a5213d02f7c27e452ad1cd893b0a668aaf6733809c31a392fc6cfc754691aca9a51582b636b92ea10abd661dd88bfd4c5f19b3ce265951728637b23fff7f7c0638721b6a01b3f1c3e923c10ea37d4e240fd973647d34dde6991cc3a04ce459c23e3ee2a858912ff78f405bbd9951935a120017904537db50f6e9e29338938f2b45ed323fc508d02fd0a0703e53ffc1889bccdec87e7c3d87e442fe29a7654d1")
+	expedctedMACSignature, _ := hex.DecodeString("66b47e29be91a7cf4803d731921482fd514b4a53a9dd1639b17705c90185f91d")
+
+	var out []byte
+	out = append(out, expectedEncryptedSignature...)
+	out = append(out, expedctedMACSignature[:20]...)
+
+	c.calcAKEKeys(c.calcDHSharedSecret())
+	result, err := c.sigMessage()
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, result, out)
+}
+
+func Test_sigMessage_increasesOurKeyId(t *testing.T) {
+	var ourKeyID uint32 = 1
+	c := newConversation(otrV3{}, fixtureRand())
+	c.initAKE()
+
+	c.ourCurrentKey = alicePrivateKey
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+	c.ake.keys.ourKeyID = ourKeyID
+
+	_, err := c.sigMessage()
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, c.ake.keys.ourKeyID, ourKeyID+1)
+}
+
+func Test_encrypt(t *testing.T) {
+	rnd := fixedRand([]string{hex.EncodeToString(fixedX().Bytes())})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ake.theirPublicValue = fixedGX()
+	io.ReadFull(c.rand(), c.ake.r[:])
+
+	encryptedGx, err := encrypt(c.ake.r[:], appendMPI(nil, c.ake.theirPublicValue))
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, len(encryptedGx), len(appendMPI([]byte{}, c.ake.theirPublicValue)))
+}
+
+func Test_decrypt(t *testing.T) {
+	rnd := fixedRand([]string{hex.EncodeToString(fixedX().Bytes())})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ake.theirPublicValue = fixedGX()
+	io.ReadFull(c.rand(), c.ake.r[:])
+
+	encryptedGx, _ := encrypt(c.ake.r[:], appendMPI(nil, c.ake.theirPublicValue))
+	decryptedGx := encryptedGx
+	err := decrypt(c.ake.r[:], decryptedGx, encryptedGx)
+
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, decryptedGx, appendMPI([]byte{}, c.ake.theirPublicValue))
+}
+
+func Test_checkDecryptedGxWithoutError(t *testing.T) {
+	hashedGx := otrV3{}.hash2(appendMPI([]byte{}, fixedGX()))
+	err := checkDecryptedGx(appendMPI([]byte{}, fixedGX()), hashedGx[:], otrV3{})
+	assertDeepEquals(t, err, nil)
+}
+
+func Test_checkDecryptedGxWithError(t *testing.T) {
+	hashedGx := otrV3{}.hash2(appendMPI([]byte{}, fixedGY()))
+	err := checkDecryptedGx(appendMPI([]byte{}, fixedGX()), hashedGx[:], otrV3{})
+	assertDeepEquals(t, err.Error(), "otr: bad commit MAC in reveal signature message")
+}
+
+func Test_extractGxWithoutError(t *testing.T) {
+	gx, err := extractGx(appendMPI([]byte{}, fixedGX()))
+	assertDeepEquals(t, err, nil)
+	assertDeepEquals(t, gx, fixedGX())
+}
+
+func Test_extractGxWithCorruptError(t *testing.T) {
+	gx, err := extractGx(appendMPI(appendMPI([]byte{}, fixedGX()), fixedY()))
+	assertDeepEquals(t, err.Error(), "otr: gx corrupt after decryption")
+	assertDeepEquals(t, gx, fixedGX())
+}
+
+func Test_extractGx_returnsErrorWhenThereIsNotEnoughLengthForTheMPI(t *testing.T) {
+	_, err := extractGx([]byte{0x00, 0x00, 0x00, 0x02, 0x01})
+	assertDeepEquals(t, err, newOtrError("gx corrupt after decryption"))
+}
+
+func Test_extractGxWithRangeError(t *testing.T) {
+	gx, err := extractGx(appendMPI([]byte{}, big.NewInt(1)))
+	assertDeepEquals(t, gx, big.NewInt(1))
+	assertDeepEquals(t, err.Error(), "otr: DH value out of range")
+}
+
+func Test_calcDHSharedSecret(t *testing.T) {
+	var bob Conversation
+	bob.initAKE()
+	bob.setSecretExponent(fixedX())
+	bob.ake.theirPublicValue = fixedGY()
+
+	sharedSecretB := bob.calcDHSharedSecret()
+	assertDeepEquals(t, sharedSecretB, expectedSharedSecret)
+
+	var alice Conversation
+	alice.initAKE()
+	alice.setSecretExponent(fixedY())
+	alice.ake.theirPublicValue = fixedGX()
+
+	sharedSecretA := alice.calcDHSharedSecret()
+
+	assertDeepEquals(t, sharedSecretA, expectedSharedSecret)
+}
+
+func Test_calcAKEKeys(t *testing.T) {
+	var bob Conversation
+	bob.version = otrV3{}
+	bob.initAKE()
+	bob.calcAKEKeys(expectedSharedSecret)
+
+	assertDeepEquals(t, bob.ssid[:], bytesFromHex("9cee5d2c7edbc86d"))
+	assertDeepEquals(t, bob.ake.revealKey.c, bytesFromHex("5745340b350364a02a0ac1467a318dcc"))
+	assertDeepEquals(t, bob.ake.sigKey.c, bytesFromHex("d942cc80b66503414c05e3752d9ba5c4"))
+	assertDeepEquals(t, bob.ake.revealKey.m1, bytesFromHex("d3251498fb9d977d07392a96eafb8c048d6bc67064bd7da72aa38f20f87a2e3d"))
+	assertDeepEquals(t, bob.ake.revealKey.m2, bytesFromHex("79c101a78a6c5819547a36b4813c84a8ac553d27a5d4b58be45dd0f3a67d3ca6"))
+	assertDeepEquals(t, bob.ake.sigKey.m1, bytesFromHex("b6254b8eab0ad98152949454d23c8c9b08e4e9cf423b27edc09b1975a76eb59c"))
+	assertDeepEquals(t, bob.ake.sigKey.m2, bytesFromHex("954be27015eeb0455250144d906e83e7d329c49581aea634c4189a3c981184f5"))
+}
+
+func Test_generateRevealKeyEncryptedSignature(t *testing.T) {
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = bobPrivateKey
+	c.setSecretExponent(fixedX())
+	c.ake.theirPublicValue = fixedGY()
+	c.ake.keys.ourKeyID = 1
+
+	key := c.calcDHSharedSecret()
+	c.calcAKEKeys(key)
+	expectedEncryptedSignature, _ := hex.DecodeString("000001d2dda2d4ef365711c172dad92804b201fcd2fdd6444568ebf0844019fb65ca4f5f57031936f9a339e08bfd4410905ab86c5d6f73e6c94de6a207f373beff3f7676faee7b1d3be21e630fe42e95db9d4ac559252bff530481301b590e2163b99bde8aa1b07448bf7252588e317b0ba2fc52f85a72a921ba757785b949e5e682341d98800aa180aa0bd01f51180d48260e4358ffae72a97f652f02eb6ae3bc6a25a317d0ca5ed0164a992240baac8e043f848332d22c10a46d12c745dc7b1b0ee37fd14614d4b69d500b8ce562040e3a4bfdd1074e2312d3e3e4c68bd15d70166855d8141f695b21c98c6055a5edb9a233925cf492218342450b806e58b3a821e5d1d2b9c6b9cbcba263908d7190a3428ace92572c064a328f86fa5b8ad2a9c76d5b9dcaeae5327f545b973795f7c655248141c2f82db0a2045e95c1936b726d6474f50283289e92ab5c7297081a54b9e70fce87603506dedd6734bab3c1567ee483cd4bcb0e669d9d97866ca274f178841dafc2acfdcd10cb0e2d07db244ff4b1d23afe253831f142083d912a7164a3425f82c95675298cf3c5eb3e096bbc95e44ecffafbb585738723c0adbe11f16c311a6cddde630b9c304717ce5b09247d482f32709ea71ced16ba930a554f9949c1acbecf")
+	expedctedMACSignature, _ := hex.DecodeString("8e6e5ef63a4e8d6aa2cfb1c5fe1831498862f69d7de32af4f9895180e4b494e6")
+
+	encryptedSig, err := c.generateEncryptedSignature(&c.ake.revealKey)
+	macSig := sumHMAC(c.ake.revealKey.m2, encryptedSig, otrV3{})
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, encryptedSig, expectedEncryptedSignature)
+	assertDeepEquals(t, macSig, expedctedMACSignature)
+}
+
+func Test_generateSigKeyEncryptedSignature(t *testing.T) {
+	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = alicePrivateKey
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+	c.ake.keys.ourKeyID = 1
+
+	key := c.calcDHSharedSecret()
+	c.calcAKEKeys(key)
+	expectedEncryptedSignature, _ := hex.DecodeString("000001d2b4f6ac650cc1d28f61a3b9bdf3cd60e2d1ea55d4c56e9f954eb22e10764861fb40d69917f5c4249fa701f3c04fae9449cd13a5054861f95fbc5775fc3cfd931cf5cc1a89eac82e7209b607c4fbf18df945e23bd0e91365fcc6c5dac072703dd8e2287372107f6a2cbb9139f5e82108d4cbcc1c6cdfcc772014136e756338745e2210d42c6e3ec4e9cf87fa8ebd8190e00f3a54bec86ee06cb7664059bb0fa79529e9d2e563ffecc5561477b3ba6bbf4ac679624b6da69a85822ed5c6ceb56a98740b1002026c503c39badab13b5d5ec948bbb961f0c90e68894a1fb70645a8e21ffe6b78e2e4ee62a62c48bd54e3d27c1166d098791518b53a10c409b5e55d16555b721a7750b7084e8972540bf0f1d76602e9b5fd58f94ed2dbf69fafccef84fdca2f9d800346b2358a200db060d8cf1b984a5213d02f7c27e452ad1cd893b0a668aaf6733809c31a392fc6cfc754691aca9a51582b636b92ea10abd661dd88bfd4c5f19b3ce265951728637b23fff7f7c0638721b6a01b3f1c3e923c10ea37d4e240fd973647d34dde6991cc3a04ce459c23e3ee2a858912ff78f405bbd9951935a120017904537db50f6e9e29338938f2b45ed323fc508d02fd0a0703e53ffc1889bccdec87e7c3d87e442fe29a7654d1")
+	expedctedMACSignature, _ := hex.DecodeString("66b47e29be91a7cf4803d731921482fd514b4a53a9dd1639b17705c90185f91d")
+
+	encryptedSig, err := c.generateEncryptedSignature(&c.ake.sigKey)
+	macSig := sumHMAC(c.ake.sigKey.m2, encryptedSig, otrV3{})
+	assertEquals(t, err, nil)
+	assertDeepEquals(t, encryptedSig, expectedEncryptedSignature)
+	assertDeepEquals(t, macSig, expedctedMACSignature)
+}
+
+func Test_processDHCommit_returnsErrorIfTheEncryptedGXPartIsNotCorrect(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	err := c.processDHCommit([]byte{0x00, 0x00, 0x00, 0x02, 0x01})
+	assertDeepEquals(t, err, newOtrError("corrupt DH commit message"))
+}
+
+func Test_processDHCommit_returnsErrorIfTheHashedGXPartIsNotCorrect(t *testing.T) {
+	c := newConversation(otrV2{}, fixtureRand())
+	err := c.processDHCommit([]byte{0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01})
+	assertDeepEquals(t, err, newOtrError("corrupt DH commit message"))
+}
+
+func Test_calcXBb_returnsErrorIfTheSigningDoesntWork(t *testing.T) {
+	c := newConversation(otrV2{}, fixedRand([]string{"AB"}))
+	c.ourCurrentKey = bobPrivateKey
+	c.ake.keys.ourKeyID = 1
+
+	_, err := c.calcXb(nil, []byte{0x00})
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_dhCommitMessage_returnsErrorIfNoRandomnessIsAvailable(t *testing.T) {
+	rnd := fixedRand([]string{"ABCD"})
+	c := newConversation(otrV3{}, rnd)
+	_, err := c.dhCommitMessage()
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_dhCommitMessage_returnsErrorIfNoRandomnessIsAvailableForR(t *testing.T) {
+	rnd := fixedRand([]string{
+		"ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD",
+		"ABCDABCDABCDABCDABCDABCDABCDAB",
+	})
+	c := newConversation(otrV3{}, rnd)
+	_, err := c.dhCommitMessage()
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_generateEncryptedSignature_returnsErrorIfCalcXbFails(t *testing.T) {
+	rnd := fixedRand([]string{"abcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = bobPrivateKey
+	c.ake.theirPublicValue = fixedGX()
+	c.ake.ourPublicValue = fixedGY()
+
+	_, err := c.generateEncryptedSignature(&c.ake.revealKey)
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_revealSigMessage_returnsErrorFromGenerateEncryptedSignature(t *testing.T) {
+	rnd := fixedRand([]string{"abcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = bobPrivateKey
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+
+	_, err := c.revealSigMessage()
+	assertDeepEquals(t, err, errShortRandomRead)
+}
+
+func Test_sigMessage_returnsErrorFromgenerateEncryptedSignature(t *testing.T) {
+	rnd := fixedRand([]string{"cbcd"})
+	c := newConversation(otrV3{}, rnd)
+	c.initAKE()
+
+	c.ourCurrentKey = bobPrivateKey
+	c.setSecretExponent(fixedY())
+	c.ake.theirPublicValue = fixedGX()
+	c.ake.keys.ourKeyID = 1
+	_, err := c.sigMessage()
+	assertEquals(t, err, errShortRandomRead)
+}
+
+func Test_processDHKey_returnsErrorIfTheMessageHasAnIncorrectGyParameter(t *testing.T) {
+	c := newConversation(otrV2{}, fixedRand([]string{}))
+	_, err := c.processDHKey([]byte{0x00, 0x00, 0x00, 0x02, 0x01})
+	assertDeepEquals(t, err, newOtrError("corrupt DH key message"))
+}
+
+func Test_processDHKey_returnsErrorIfGyIsNotAValidDHParameter(t *testing.T) {
+	c := newConversation(otrV2{}, fixedRand([]string{}))
+	_, err := c.processDHKey([]byte{0x00, 0x00, 0x00, 0x01, 0x01})
+	assertDeepEquals(t, err, newOtrError("DH value out of range"))
+}
diff --git a/.pc/test_location.patch/keys_test.go b/.pc/test_location.patch/keys_test.go
new file mode 100644
index 0000000..04c8eaf
--- /dev/null
+++ b/.pc/test_location.patch/keys_test.go
@@ -0,0 +1,1082 @@
+package otr3
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/rand"
+	"os"
+	"syscall"
+	"testing"
+)
+
+var (
+	serializedPublicKey = []byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	}
+	serializedPrivateKey = []byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+
+		// len of x MPI
+		0x00, 0x00, 0x00, 0x14,
+		// y MPI
+		0x14, 0xD0, 0x34, 0x5A, 0x35, 0x62, 0xC4, 0x80, 0xA0, 0x39, 0xE3, 0xC7, 0x27, 0x64, 0xF7, 0x2D, 0x79, 0x04, 0x32, 0x16,
+	}
+)
+
+func inp(s string) *bufio.Reader {
+	return bufio.NewReader(bytes.NewBuffer([]byte(s)))
+}
+
+func Test_readParameter_willReturnTheParameterRead(t *testing.T) {
+	tag, value, _, _ := readParameter(inp(`(p #00FC07ABCF0DC916AFF6E9A0D450A9B7A857#)`))
+	assertDeepEquals(t, tag, "p")
+	assertDeepEquals(t, value, bnFromHex("00FC07ABCF0DC916AFF6E9A0D450A9B7A857"))
+}
+
+func Test_readParameter_willReturnAnotherParameterRead(t *testing.T) {
+	tag, value, _, _ := readParameter(inp(`(quux #00FC07ABCF0DC916AFF6E9A0D450A9B7A858#)`))
+	assertDeepEquals(t, tag, "quux")
+	assertDeepEquals(t, value, bnFromHex("00FC07ABCF0DC916AFF6E9A0D450A9B7A858"))
+}
+
+func Test_readParameter_willReturnNotOKIfAskedToParseATooShortList(t *testing.T) {
+	_, _, _, ok := readParameter(inp(`()`))
+	assertDeepEquals(t, ok, false)
+
+	_, _, _, ok = readParameter(inp(`(quux)`))
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readParameter_willReturnNotOKIfAskedToParseSomethingOfTheWrongType(t *testing.T) {
+	_, _, _, ok := readParameter(inp(`("quux" #00FC07ABCF0DC916AFF6E9A0D450A9B7A858#)`))
+	assertDeepEquals(t, ok, false)
+
+	_, _, _, ok = readParameter(inp(`(quux "00FC07ABCF0DC916AFF6E9A0D450A9B7A858")`))
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnADSAPrivateKey(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#)
+  )`)
+	k, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, k.P, bnFromHex("00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857"))
+	assertDeepEquals(t, k.Q, bnFromHex("00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081"))
+	assertDeepEquals(t, k.G, bnFromHex("535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26"))
+	assertDeepEquals(t, k.X, bnFromHex("14D0345A3562C480A039E3C72764F72D79043216"))
+	assertDeepEquals(t, k.Y, bnFromHex("0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKForNoList(t *testing.T) {
+	from := inp(`dsa`)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKForListWithNoEntries(t *testing.T) {
+	from := inp(`()`)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKForListWithNoEnding(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#)
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKForListWithTheWrongTag(t *testing.T) {
+	from := inp(`(dsax
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#)
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKForListWithInvalidTypeOfTag(t *testing.T) {
+	from := inp(`("dsa"
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#)
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKWhenPParameterIsInvalid(t *testing.T) {
+	from := inp(`(dsa
+  (px #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#))
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKWhenQParameterIsInvalid(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (qx #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#))
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKWhenGParameterIsInvalid(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (gx #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#))
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKWhenYParameterIsInvalid(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (yx #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#))
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readDSAPrivateKey_willReturnNotOKWhenXParameterIsInvalid(t *testing.T) {
+	from := inp(`(dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (xx #14D0345A3562C480A039E3C72764F72D79043216#))
+  `)
+	_, ok := readDSAPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnAPrivateKey(t *testing.T) {
+	from := inp(`(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	k, ok := readPrivateKey(from)
+	assertDeepEquals(t, k.(*DSAPrivateKey).PrivateKey.P, bnFromHex("00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857"))
+	assertDeepEquals(t, k.(*DSAPrivateKey).PrivateKey.Q, bnFromHex("00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081"))
+	assertDeepEquals(t, k.(*DSAPrivateKey).PrivateKey.G, bnFromHex("535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26"))
+	assertDeepEquals(t, k.(*DSAPrivateKey).PrivateKey.X, bnFromHex("14D0345A3562C480A039E3C72764F72D79043217"))
+	assertDeepEquals(t, k.(*DSAPrivateKey).PrivateKey.Y, bnFromHex("0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readPrivateKey_willReturnNotOKForSomethingNotAList(t *testing.T) {
+	from := inp(`one`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnNotOKForAListThatIsNotEnded(t *testing.T) {
+	from := inp(`(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnNotOKForAnInvalidDSAKey(t *testing.T) {
+	from := inp(`(private-key (dsax
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnNotOKForAnInvalidTag(t *testing.T) {
+	from := inp(`(private-keyx (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnNotOKForATagOfWrongType(t *testing.T) {
+	from := inp(`("private-key" (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readPrivateKey_willReturnNotOKForNoTag(t *testing.T) {
+	from := inp(`("private-key" (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	_, ok := readPrivateKey(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnAnAccount(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(protocol libpurple-Jabber)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  )))`)
+	k, ok, _ := readAccount(from)
+	assertDeepEquals(t, k.Name, "foo")
+	assertDeepEquals(t, k.Protocol, "libpurple-Jabber")
+	assertDeepEquals(t, k.Key.(*DSAPrivateKey).PrivateKey.P, bnFromHex("00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readAccount_willReturnNotOKForSomethingNotAList(t *testing.T) {
+	from := inp(`account`)
+	_, ok, atEnd := readAccount(from)
+	assertDeepEquals(t, ok, true)
+	assertDeepEquals(t, atEnd, true)
+}
+
+func Test_readAccount_willReturnNotOKForAListThatIsNotEnded(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(protocol libpurple-Jabber)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  ))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAMissingName(t *testing.T) {
+	from := inp(`(account
+(protocol libpurple-Jabber)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAMissingProtocol(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAMissingPrivateKey(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(protocol libpurple-Jabber)
+)`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAnIncorrectName(t *testing.T) {
+	from := inp(`(account
+(namex "foo")
+(protocol libpurple-Jabber)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAnIncorrectProtocol(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(protocolx libpurple-Jabber)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccount_willReturnNotOKForAnIncorrectPrivateKey(t *testing.T) {
+	from := inp(`(account
+(name "foo")
+(protocol libpurple-Jabber)
+(private-keyx (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043217#)
+  )))`)
+	_, ok, _ := readAccount(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnTheAccountRead(t *testing.T) {
+	from := inp(`(privkeys (account
+(name "foo2")
+(protocol libpurple-Jabberx)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858#)
+  ))))`)
+	k, ok := readAccounts(from)
+	assertDeepEquals(t, k[0].Name, "foo2")
+	assertDeepEquals(t, k[0].Protocol, "libpurple-Jabberx")
+	assertDeepEquals(t, k[0].Key.(*DSAPrivateKey).PrivateKey.P, bnFromHex("00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readAccounts_willReturnZeroAccountsIfNoAccountsThere(t *testing.T) {
+	from := inp(`(privkeys)`)
+	k, ok := readAccounts(from)
+	assertDeepEquals(t, len(k), 0)
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readAccounts_willReturnNotOKForNoList(t *testing.T) {
+	from := inp(`privkeys`)
+	_, ok := readAccounts(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnNotOKForNonFinishedList(t *testing.T) {
+	from := inp(`(privkeys`)
+	_, ok := readAccounts(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnNotOKForIncorrectTag(t *testing.T) {
+	from := inp(`(privkeysx)`)
+	_, ok := readAccounts(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnNotOKForTagWithWrongType(t *testing.T) {
+	from := inp(`("privkeys")`)
+	_, ok := readAccounts(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnNotOKForAccountThatIsNotOK(t *testing.T) {
+	from := inp(`(privkeys
+(accountx
+	(name "2")
+	(protocol libpurple-jabber-gtalk)
+	(private-key
+	 (dsa
+	  (p #00F24843F9447B62138AE49BF83188D1353ADA5CAC118890CFDEC01BF349D75E887B19C221665C7857CAD583AF656C67FB04A99FD8F8D69D09C9529C6C14D426F1E3924DC9243AF2970E3E4B04A23489A09E8A90E7E81EBA763AD4F0636B8A43415B6FC16A02C3624CE76272FA00783C8DB850D3A996B58136F7A0EB80AE0BC613#)
+	  (q #00D16B2607FCBC0EDC639F763A54F34475B1CC8473#)
+	  (g #00B15AFEF5F96EFEE41006F136C23A18849DA8133069A879D083F7C7AA362E187DAE3ED0C4F372D0D4E3AAE567008A1872A6E85D8F84E53A3FE1B352AF0B4E2F0CB033A6D34285ECD3E4A93653BDE99C3A8D840D9D35F82AC2FA8539DB6C7F7A1DAD77FEECD62803757FF1E2DE4CEC4A5A2AD643271514DDEEEF3D008F66FBF9DB#)
+	  (y #01F9BE7DA0E4E84774048058B53202B2704BF688A306092ED533A55E68EABA814C8D62F45AAD8FF30C3055DCA461B7DBA6B78938FC4D69780A830C6457CC107F3D275C21D00E53147C14162176C77169D3BCA586DC30F15F4B482160E276869AA336F38AF7FC3686A764AB5A02C751D921A42B8B9AE8E06918059CD73C424154#)
+	  (x #00943480B228FC0D3D7ADFC91F680FC415E1306333#)
+	  )
+	 )
+	 ))`)
+	_, ok := readAccounts(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccounts_willReturnMoreThanOneAccount(t *testing.T) {
+	from := inp(`(privkeys (account
+(name "foo2")
+(protocol libpurple-Jabberx)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858#)
+  )))
+	(account
+	(name "2")
+	(protocol libpurple-jabber-gtalk)
+	(private-key
+	 (dsa
+	  (p #00F24843F9447B62138AE49BF83188D1353ADA5CAC118890CFDEC01BF349D75E887B19C221665C7857CAD583AF656C67FB04A99FD8F8D69D09C9529C6C14D426F1E3924DC9243AF2970E3E4B04A23489A09E8A90E7E81EBA763AD4F0636B8A43415B6FC16A02C3624CE76272FA00783C8DB850D3A996B58136F7A0EB80AE0BC613#)
+	  (q #00D16B2607FCBC0EDC639F763A54F34475B1CC8473#)
+	  (g #00B15AFEF5F96EFEE41006F136C23A18849DA8133069A879D083F7C7AA362E187DAE3ED0C4F372D0D4E3AAE567008A1872A6E85D8F84E53A3FE1B352AF0B4E2F0CB033A6D34285ECD3E4A93653BDE99C3A8D840D9D35F82AC2FA8539DB6C7F7A1DAD77FEECD62803757FF1E2DE4CEC4A5A2AD643271514DDEEEF3D008F66FBF9DB#)
+	  (y #01F9BE7DA0E4E84774048058B53202B2704BF688A306092ED533A55E68EABA814C8D62F45AAD8FF30C3055DCA461B7DBA6B78938FC4D69780A830C6457CC107F3D275C21D00E53147C14162176C77169D3BCA586DC30F15F4B482160E276869AA336F38AF7FC3686A764AB5A02C751D921A42B8B9AE8E06918059CD73C424154#)
+	  (x #00943480B228FC0D3D7ADFC91F680FC415E1306333#)
+	  )
+	 )
+	 )
+	)`)
+	k, ok := readAccounts(from)
+	assertDeepEquals(t, k[0].Name, "foo2")
+	assertDeepEquals(t, k[0].Protocol, "libpurple-Jabberx")
+	assertDeepEquals(t, k[0].Key.(*DSAPrivateKey).PrivateKey.P, bnFromHex("00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858"))
+	assertDeepEquals(t, k[1].Name, "2")
+	assertDeepEquals(t, k[1].Protocol, "libpurple-jabber-gtalk")
+	assertDeepEquals(t, k[1].Key.(*DSAPrivateKey).PrivateKey.Q, bnFromHex("00D16B2607FCBC0EDC639F763A54F34475B1CC8473"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_PublicKey_parse_ParsePofAPublicKeyCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse(serializedPublicKey)
+
+	assertDeepEquals(t, pk.P, bnFromHex("00F24843F9447B62138AE49BF83188D1353ADA5CAC118890CFDEC01BF349D75E887B19C221665C7857CAD583AF656C67FB04A99FD8F8D69D09C9529C6C14D426F1E3924DC9243AF2970E3E4B04A23489A09E8A90E7E81EBA763AD4F0636B8A43415B6FC16A02C3624CE76272FA00783C8DB850D3A996B58136F7A0EB80AE0BC613"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfThereIsTooLittleDataForTheKeyTypeTag(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{0x00})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfTheTypeTagIsNotCorrect(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for something else
+		0x00, 0x01,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfPCannotBeParsedCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x10, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfQCannotBeParsedCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x10, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfGCannotBeParsedCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x10, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfYCannotBeParsedCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x10, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ReturnsNotOKIfParametersAreMissing(t *testing.T) {
+	pk := &DSAPublicKey{}
+	_, ok := pk.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+	})
+
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_parse_ParseQofAPublicKeyCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(serializedPublicKey)
+
+	assertDeepEquals(t, pk.Q, bnFromHex("00D16B2607FCBC0EDC639F763A54F34475B1CC8473"))
+}
+
+func Test_PublicKey_parse_ParseGofAPublicKeyCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(serializedPublicKey)
+
+	assertDeepEquals(t, pk.G, bnFromHex("00B15AFEF5F96EFEE41006F136C23A18849DA8133069A879D083F7C7AA362E187DAE3ED0C4F372D0D4E3AAE567008A1872A6E85D8F84E53A3FE1B352AF0B4E2F0CB033A6D34285ECD3E4A93653BDE99C3A8D840D9D35F82AC2FA8539DB6C7F7A1DAD77FEECD62803757FF1E2DE4CEC4A5A2AD643271514DDEEEF3D008F66FBF9DB"))
+}
+
+func Test_PublicKey_parse_ParseYofAPublicKeyCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(serializedPublicKey)
+
+	assertDeepEquals(t, pk.Y, bnFromHex("01F9BE7DA0E4E84774048058B53202B2704BF688A306092ED533A55E68EABA814C8D62F45AAD8FF30C3055DCA461B7DBA6B78938FC4D69780A830C6457CC107F3D275C21D00E53147C14162176C77169D3BCA586DC30F15F4B482160E276869AA336F38AF7FC3686A764AB5A02C751D921A42B8B9AE8E06918059CD73C424154"))
+}
+
+func Test_PrivateKey_parse_ParsePublicKeyofAPrivateKeyCorrectly(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	pk := &DSAPublicKey{}
+	priv.Parse(serializedPrivateKey)
+	pk.Parse(serializedPublicKey)
+
+	assertDeepEquals(t, priv.PublicKey(), pk)
+}
+
+func Test_PrivateKey_parse_ParseXofAPrivateKeyCorrectly(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	_, ok := priv.Parse(serializedPrivateKey)
+	assertDeepEquals(t, priv.X, bnFromHex("14D0345A3562C480A039E3C72764F72D79043216"))
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_PrivateKey_parse_ReturnsNotOKIfPublicKeyIsNotOK(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	_, ok := priv.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA,
+
+		// len of x MPI
+		0x00, 0x00, 0x00, 0x14,
+		// x MPI
+		0x14, 0xD0, 0x34, 0x5A, 0x35, 0x62, 0xC4, 0x80, 0xA0, 0x39, 0xE3, 0xC7, 0x27, 0x64, 0xF7, 0x2D, 0x79, 0x04, 0x32, 0x16,
+	})
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PrivateKey_parse_ReturnsNotOKIfPrivateKeyIsNotOK(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	_, ok := priv.Parse([]byte{
+		// key type for DSA
+		0x00, 0x00,
+
+		// len of p MPI
+		0x00, 0x00, 0x00, 0x80,
+		// p MPI
+		0xF2, 0x48, 0x43, 0xF9, 0x44, 0x7B, 0x62, 0x13, 0x8A, 0xE4, 0x9B, 0xF8, 0x31, 0x88, 0xD1, 0x35, 0x3A, 0xDA, 0x5C, 0xAC, 0x11, 0x88, 0x90, 0xCF, 0xDE, 0xC0, 0x1B, 0xF3, 0x49, 0xD7, 0x5E, 0x88, 0x7B, 0x19, 0xC2, 0x21, 0x66, 0x5C, 0x78, 0x57, 0xCA, 0xD5, 0x83, 0xAF, 0x65, 0x6C, 0x67, 0xFB, 0x04, 0xA9, 0x9F, 0xD8, 0xF8, 0xD6, 0x9D, 0x09, 0xC9, 0x52, 0x9C, 0x6C, 0x14, 0xD4, 0x26, 0xF1, 0xE3, 0x92, 0x4D, 0xC9, 0x24, 0x3A, 0xF2, 0x97, 0x0E, 0x3E, 0x4B, 0x04, 0xA2, 0x34, 0x89, 0xA0, 0x9E, 0x8A, 0x90, 0xE7, 0xE8, 0x1E, 0xBA, 0x76, 0x3A, 0xD4, 0xF0, 0x63, 0x6B, 0x8A, 0x43, 0x41, 0x5B, 0x6F, 0xC1, 0x6A, 0x02, 0xC3, 0x62, 0x4C, 0xE7, 0x62, 0x72, 0xFA, 0x00, 0x78, 0x3C, 0x8D, 0xB8, 0x50, 0xD3, 0xA9, 0x96, 0xB5, 0x81, 0x36, 0xF7, 0xA0, 0xEB, 0x80, 0xAE, 0x0B, 0xC6, 0x13,
+
+		// len of q MPI
+		0x00, 0x00, 0x00, 0x14,
+		// q MPI
+		0xD1, 0x6B, 0x26, 0x07, 0xFC, 0xBC, 0x0E, 0xDC, 0x63, 0x9F, 0x76, 0x3A, 0x54, 0xF3, 0x44, 0x75, 0xB1, 0xCC, 0x84, 0x73,
+
+		// len of g MPI
+		0x00, 0x00, 0x00, 0x80,
+		// g MPI
+		0xB1, 0x5A, 0xFE, 0xF5, 0xF9, 0x6E, 0xFE, 0xE4, 0x10, 0x06, 0xF1, 0x36, 0xC2, 0x3A, 0x18, 0x84, 0x9D, 0xA8, 0x13, 0x30, 0x69, 0xA8, 0x79, 0xD0, 0x83, 0xF7, 0xC7, 0xAA, 0x36, 0x2E, 0x18, 0x7D, 0xAE, 0x3E, 0xD0, 0xC4, 0xF3, 0x72, 0xD0, 0xD4, 0xE3, 0xAA, 0xE5, 0x67, 0x00, 0x8A, 0x18, 0x72, 0xA6, 0xE8, 0x5D, 0x8F, 0x84, 0xE5, 0x3A, 0x3F, 0xE1, 0xB3, 0x52, 0xAF, 0x0B, 0x4E, 0x2F, 0x0C, 0xB0, 0x33, 0xA6, 0xD3, 0x42, 0x85, 0xEC, 0xD3, 0xE4, 0xA9, 0x36, 0x53, 0xBD, 0xE9, 0x9C, 0x3A, 0x8D, 0x84, 0x0D, 0x9D, 0x35, 0xF8, 0x2A, 0xC2, 0xFA, 0x85, 0x39, 0xDB, 0x6C, 0x7F, 0x7A, 0x1D, 0xAD, 0x77, 0xFE, 0xEC, 0xD6, 0x28, 0x03, 0x75, 0x7F, 0xF1, 0xE2, 0xDE, 0x4C, 0xEC, 0x4A, 0x5A, 0x2A, 0xD6, 0x43, 0x27, 0x15, 0x14, 0xDD, 0xEE, 0xEF, 0x3D, 0x00, 0x8F, 0x66, 0xFB, 0xF9, 0xDB,
+
+		// len of y MPI
+		0x00, 0x00, 0x00, 0x80,
+		// y MPI
+		0x01, 0xF9, 0xBE, 0x7D, 0xA0, 0xE4, 0xE8, 0x47, 0x74, 0x04, 0x80, 0x58, 0xB5, 0x32, 0x02, 0xB2, 0x70, 0x4B, 0xF6, 0x88, 0xA3, 0x06, 0x09, 0x2E, 0xD5, 0x33, 0xA5, 0x5E, 0x68, 0xEA, 0xBA, 0x81, 0x4C, 0x8D, 0x62, 0xF4, 0x5A, 0xAD, 0x8F, 0xF3, 0x0C, 0x30, 0x55, 0xDC, 0xA4, 0x61, 0xB7, 0xDB, 0xA6, 0xB7, 0x89, 0x38, 0xFC, 0x4D, 0x69, 0x78, 0x0A, 0x83, 0x0C, 0x64, 0x57, 0xCC, 0x10, 0x7F, 0x3D, 0x27, 0x5C, 0x21, 0xD0, 0x0E, 0x53, 0x14, 0x7C, 0x14, 0x16, 0x21, 0x76, 0xC7, 0x71, 0x69, 0xD3, 0xBC, 0xA5, 0x86, 0xDC, 0x30, 0xF1, 0x5F, 0x4B, 0x48, 0x21, 0x60, 0xE2, 0x76, 0x86, 0x9A, 0xA3, 0x36, 0xF3, 0x8A, 0xF7, 0xFC, 0x36, 0x86, 0xA7, 0x64, 0xAB, 0x5A, 0x02, 0xC7, 0x51, 0xD9, 0x21, 0xA4, 0x2B, 0x8B, 0x9A, 0xE8, 0xE0, 0x69, 0x18, 0x05, 0x9C, 0xD7, 0x3C, 0x42, 0x41, 0x54,
+
+		// len of x MPI
+		0x00, 0x00, 0x10, 0x14,
+		// x MPI
+		0x14, 0xD0, 0x34, 0x5A, 0x35, 0x62, 0xC4, 0x80, 0xA0, 0x39, 0xE3, 0xC7, 0x27, 0x64, 0xF7, 0x2D, 0x79, 0x04, 0x32, 0x16,
+	})
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_PublicKey_serialize_willSerializeAPublicKeyCorrectly(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(serializedPublicKey)
+	result := pk.serialize()
+	assertDeepEquals(t, result, serializedPublicKey)
+}
+
+func Test_PublicKey_serialize_returnsEmptyForNil(t *testing.T) {
+	pk := &DSAPublicKey{}
+	result := pk.serialize()
+	assertNil(t, result)
+}
+
+func Test_PrivateKey_roundTripGeneratesCorrectValue(t *testing.T) {
+	pk := &DSAPrivateKey{}
+	pk.Parse(serializedPrivateKey)
+	result := pk.serialize()
+	assertDeepEquals(t, result, serializedPrivateKey)
+}
+
+func Test_PublicKey_fingerprint_willGenerateACorrectFingerprint(t *testing.T) {
+	priv := parseIntoPrivateKey("000000000080c81c2cb2eb729b7e6fd48e975a932c638b3a9055478583afa46755683e30102447f6da2d8bec9f386bbb5da6403b0040fee8650b6ab2d7f32c55ab017ae9b6aec8c324ab5844784e9a80e194830d548fb7f09a0410df2c4d5c8bc2b3e9ad484e65412be689cf0834694e0839fb2954021521ffdffb8f5c32c14dbf2020b3ce7500000014da4591d58def96de61aea7b04a8405fe1609308d000000808ddd5cb0b9d66956e3dea5a915d9aba9d8a6e7053b74dadb2fc52f9fe4e5bcc487d2305485ed95fed026ad93f06ebb8c9e8baf693b7887132c7ffdd3b0f72f4002ff4ed56583ca7c54458f8c068ca3e8a4dfa309d1dd5d34e2a4b68e6f4338835e5e0fb4317c9e4c7e4806dafda3ef459cd563775a586dd91b1319f72621bf3f00000080b8147e74d8c45e6318c37731b8b33b984a795b3653c2cd1d65cc99efe097cb7eb2fa49569bab5aab6e8a1c261a27d0f7840a5e80b317e6683042b59b6dceca2879c6ffc877a465be690c15e4a42f9a7588e79b10faac11b1ce3741fcef7aba8ce05327a2c16d279ee1b3d77eb783fb10e3356caa25635331e26dd42b8396c4d00000001420bec691fea37ecea58a5c717142f0b804452f57")
+	expectedFingerprint := bytesFromHex("0bb01c360424522e94ee9c346ce877a1a4288b2f")
+	assertDeepEquals(t, priv.PublicKey().Fingerprint(), expectedFingerprint)
+}
+
+func Test_PublicKey_fingerprint_generatesForEmpty(t *testing.T) {
+	pk := &DSAPublicKey{}
+	result := pk.Fingerprint()
+	assertNil(t, result)
+}
+
+func Test_PublicKey_Verify_willReturnOK(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(bytesFromHex("000000000080a5138eb3d3eb9c1d85716faecadb718f87d31aaed1157671d7fee7e488f95e8e0ba60ad449ec732710a7dec5190f7182af2e2f98312d98497221dff160fd68033dd4f3a33b7c078d0d9f66e26847e76ca7447d4bab35486045090572863d9e4454777f24d6706f63e02548dfec2d0a620af37bbc1d24f884708a212c343b480d00000014e9c58f0ea21a5e4dfd9f44b6a9f7f6a9961a8fa9000000803c4d111aebd62d3c50c2889d420a32cdf1e98b70affcc1fcf44d59cca2eb019f6b774ef88153fb9b9615441a5fe25ea2d11b74ce922ca0232bd81b3c0fcac2a95b20cb6e6c0c5c1ace2e26f65dc43c751af0edbb10d669890e8ab6beea91410b8b2187af1a8347627a06ecea7e0f772c28aae9461301e83884860c9b656c722f0000008065af8625a555ea0e008cd04743671a3cda21162e83af045725db2eb2bb52712708dc0cc1a84c08b3649b88a966974bde27d8612c2861792ec9f08786a246fcadd6d8d3a81a32287745f309238f47618c2bd7612cb8b02d940571e0f30b96420bcd462ff542901b46109b1e5ad6423744448d20a57818a8cbb1647d0fea3b664e"))
+	hashed := bytesFromHex("122773a99f5eafbaaa04b419b5c417b9949ce11bf199ea1bee3586619b94bb29")
+	sig := bytesFromHex("2e9e1c92773e6e51541f47f674f17e24138c48af2c86aea3e5689bd9116b5d6d28562c0aeb84a989")
+	result, ok := pk.Verify(hashed, sig)
+	assertEquals(t, ok, true)
+	assertDeepEquals(t, result, sig[20*2:])
+}
+
+func Test_PublicKey_Verify_willReturnNotOK(t *testing.T) {
+	pk := &DSAPublicKey{}
+	pk.Parse(serializedPublicKey)
+	hashed := bytesFromHex("122773a99f5eafbaaa04b419b5c417b9949ce11bf199ea1bee3586619b94bb29")
+	sig := bytesFromHex("2e9e1c92773e6e51541f47f674f17e24138c48af2c86aea3e5689bd9116b5d6d28562c0aeb84a989")
+	result, ok := pk.Verify(hashed, sig)
+	assertEquals(t, ok, false)
+	assertDeepEquals(t, result, sig[20*2:])
+}
+
+func Test_readAccountName_willSignalNotOKIfNoListIsGiven(t *testing.T) {
+	from := inp(`name`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfNoCompleteListIsGiven(t *testing.T) {
+	from := inp(`(name "foo"`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfNoNameValueIsGiven(t *testing.T) {
+	from := inp(`(name)`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfNoTagIsGiven(t *testing.T) {
+	from := inp(`()`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfTagIsTheWrongType(t *testing.T) {
+	from := inp(`("blarg" "foo")`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfTagIsNotTheSymbolName(t *testing.T) {
+	from := inp(`(namex "foo")`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalNotOKIfValueIsTheWrongType(t *testing.T) {
+	from := inp(`(name #42)`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountName_willSignalOKIfTagAndValueIsCorrect(t *testing.T) {
+	from := inp(`(name "foo")`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readAccountName_willSignalOKIfTagAndValueAsSymbolIsCorrect(t *testing.T) {
+	from := inp(`(name foo)`)
+	_, ok := readAccountName(from)
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfNoListIsGiven(t *testing.T) {
+	from := inp(`protocol`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfNoCompleteListIsGiven(t *testing.T) {
+	from := inp(`(protocol libpurple`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfNoProtocolValueIsGiven(t *testing.T) {
+	from := inp(`(protocol)`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfNoTagIsGiven(t *testing.T) {
+	from := inp(`()`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfTagIsTheWrongType(t *testing.T) {
+	from := inp(`("protocol" libpurple)`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfTagIsNotTheSymbolProtocol(t *testing.T) {
+	from := inp(`(protocolx libpurple)`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalNotOKIfValueIsTheWrongType(t *testing.T) {
+	from := inp(`(protocol "libpurple")`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, false)
+}
+
+func Test_readAccountProtocol_willSignalOKIfTagAndValueIsCorrect(t *testing.T) {
+	from := inp(`(protocol libpurple)`)
+	_, ok := readAccountProtocol(from)
+	assertDeepEquals(t, ok, true)
+}
+
+func Test_ImportKeys_willReturnARelevantErrorForIncorrectData(t *testing.T) {
+	from := bytes.NewBuffer([]byte(`(privkeys (account
+(name "foo2")
+(protocol libpurple-Jabberx)
+(private-key (dsa
+  (px #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858#)
+  ))))`))
+	_, err := ImportKeys(from)
+	assertDeepEquals(t, err, newOtrError("couldn't import data into private key"))
+}
+
+func Test_ImportKeys_willReturnTheParsedAccountInformation(t *testing.T) {
+	from := bytes.NewBuffer([]byte(`(privkeys (account
+(name "foo2")
+(protocol libpurple-Jabberx)
+(private-key (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A858#)
+  ))))`))
+	res, err := ImportKeys(from)
+	assertDeepEquals(t, len(res), 1)
+	assertDeepEquals(t, err, nil)
+}
+
+func Test_ImportKeysFromFile_willReturnAnErrorIfAskedToReadAFileNameThatDoesntExist(t *testing.T) {
+	_, err := ImportKeysFromFile("this_file_doesnt_exist.asc")
+	assertDeepEquals(t, err, &os.PathError{
+		Op:   "open",
+		Path: "this_file_doesnt_exist.asc",
+		Err:  syscall.Errno(0x02)})
+}
+
+func Test_ImportKeysFromFile_willReturnAValidAccountReadFromAFile(t *testing.T) {
+	res, err := ImportKeysFromFile("test_resources/valid_key.asc")
+	assertDeepEquals(t, len(res), 1)
+	assertDeepEquals(t, err, nil)
+}
+
+func Test_ImportKeysFromFile_willReturnAnErrorIfTheFileIsinvalid(t *testing.T) {
+	_, err := ImportKeysFromFile("test_resources/invalid_key.asc")
+	assertDeepEquals(t, err, newOtrError("couldn't import data into private key"))
+}
+
+func Test_PrivateKey_ImportWithoutError(t *testing.T) {
+	const libOTRPrivateKey = `(privkeys
+ (account
+(name "foo@example.com")
+(protocol prpl-jabber)
+(private-key
+ (dsa
+  (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+  (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+  (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+  (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+  (x #14D0345A3562C480A039E3C72764F72D79043216#)
+  )
+ )
+ )
+)`
+	priv := &DSAPrivateKey{}
+	ok := priv.Import([]byte(libOTRPrivateKey))
+	assertEquals(t, ok, true)
+}
+
+func Test_PrivateKey_GenerateWithoutError(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	err := priv.Generate(rand.Reader)
+	assertEquals(t, err, nil)
+}
+
+func Test_PrivateKey_GenerateErrorWhenGenerateParams(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	err := priv.Generate(fixedRand([]string{"ABCDEF"}))
+	assertEquals(t, err.Error(), "unexpected EOF")
+}
+
+func Test_notHex(t *testing.T) {
+	var isNotHex bool
+	testString := "o0"
+	isNotHex = notHex(rune(testString[0]))
+	assertEquals(t, isNotHex, true)
+	isNotHex = notHex(rune(testString[1]))
+	assertEquals(t, isNotHex, false)
+}
+
+func Test_exportAccounts_exportsAccounts(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	priv.Parse(serializedPrivateKey)
+	acc := Account{Name: "hello", Protocol: "go-xmpp", Key: priv}
+	bt := bytes.NewBuffer(make([]byte, 0, 200))
+	exportAccounts([]*Account{&acc}, bt)
+	assertDeepEquals(t, bt.String(),
+		`(privkeys
+  (account
+    (name "hello")
+    (protocol go-xmpp)
+    (private-key
+      (dsa
+        (p #F24843F9447B62138AE49BF83188D1353ADA5CAC118890CFDEC01BF349D75E887B19C221665C7857CAD583AF656C67FB04A99FD8F8D69D09C9529C6C14D426F1E3924DC9243AF2970E3E4B04A23489A09E8A90E7E81EBA763AD4F0636B8A43415B6FC16A02C3624CE76272FA00783C8DB850D3A996B58136F7A0EB80AE0BC613#)
+        (q #D16B2607FCBC0EDC639F763A54F34475B1CC8473#)
+        (g #B15AFEF5F96EFEE41006F136C23A18849DA8133069A879D083F7C7AA362E187DAE3ED0C4F372D0D4E3AAE567008A1872A6E85D8F84E53A3FE1B352AF0B4E2F0CB033A6D34285ECD3E4A93653BDE99C3A8D840D9D35F82AC2FA8539DB6C7F7A1DAD77FEECD62803757FF1E2DE4CEC4A5A2AD643271514DDEEEF3D008F66FBF9DB#)
+        (y #1F9BE7DA0E4E84774048058B53202B2704BF688A306092ED533A55E68EABA814C8D62F45AAD8FF30C3055DCA461B7DBA6B78938FC4D69780A830C6457CC107F3D275C21D00E53147C14162176C77169D3BCA586DC30F15F4B482160E276869AA336F38AF7FC3686A764AB5A02C751D921A42B8B9AE8E06918059CD73C424154#)
+        (x #14D0345A3562C480A039E3C72764F72D79043216#)
+      )
+    )
+  )
+)
+`)
+}
+
+func Test_ExportKeysToFile_exportsKeysToAFile(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	priv.Parse(serializedPrivateKey)
+	acc := &Account{Name: "hello", Protocol: "go-xmpp", Key: priv}
+
+	err := ExportKeysToFile([]*Account{acc}, "test_resources/test_export_of_keys.blah")
+	assertNil(t, err)
+
+	res, err2 := ImportKeysFromFile("test_resources/test_export_of_keys.blah")
+
+	defer os.Remove("test_resources/test_export_of_keys.blah")
+
+	assertNil(t, err2)
+	assertDeepEquals(t, res[0].Key, acc.Key)
+}
+
+func Test_ExportKeysToFile_returnsAnErrorIfSomethingGoesWrong(t *testing.T) {
+	priv := &DSAPrivateKey{}
+	priv.Parse(serializedPrivateKey)
+	acc := &Account{Name: "hello", Protocol: "go-xmpp", Key: priv}
+
+	err := ExportKeysToFile([]*Account{acc}, "non_existing_directory/test_export_of_keys.blah")
+	assertDeepEquals(t, err.Error(), "open non_existing_directory/test_export_of_keys.blah: no such file or directory")
+}
diff --git a/ake.go b/ake.go
index ec8c367..01a220f 100644
--- a/ake.go
+++ b/ake.go
@@ -87,7 +87,7 @@ func (c *Conversation) calcXb(key *akeKeys, mb []byte) ([]byte, error) {
 	xb = appendWord(xb, c.ake.keys.ourKeyID)
 
 	sigb, err := c.ourCurrentKey.Sign(c.rand(), mb)
-	if err == io.ErrUnexpectedEOF {
+	if err == io.ErrUnexpectedEOF || err == io.EOF {
 		return nil, errShortRandomRead
 	}
 
diff --git a/ake_test.go b/ake_test.go
index b16bc2f..8ea6d14 100644
--- a/ake_test.go
+++ b/ake_test.go
@@ -55,7 +55,10 @@ func Test_dhKeyMessage_returnsAnErrorIfTheresNotEnoughRandomnessForAnMPI(t *test
 }
 
 func Test_revealSigMessage(t *testing.T) {
-	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+	})
 	c := newConversation(otrV3{}, rnd)
 
 	c.ourCurrentKey = bobPrivateKey
@@ -175,7 +178,10 @@ func Test_processEncryptedSigWithBadSignatureError(t *testing.T) {
 }
 
 func Test_processRevealSig(t *testing.T) {
-	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+	})
 	bob := newConversation(otrV3{}, rnd)
 	bob.initAKE()
 	alice := newConversation(otrV3{}, rnd)
@@ -198,7 +204,9 @@ func Test_processRevealSig(t *testing.T) {
 }
 
 func Test_processSig(t *testing.T) {
-	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
 	alice := newConversation(otrV3{}, rnd)
 	alice.initAKE()
 	alice.ourCurrentKey = bobPrivateKey
@@ -238,7 +246,8 @@ func Test_processRevealSig_returnsErrorIfTheSignatureDataIsInvalid(t *testing.T)
 }
 
 func Test_sigMessage(t *testing.T) {
-	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
 	c := newConversation(otrV3{}, rnd)
 	c.initAKE()
 
@@ -373,7 +382,9 @@ func Test_calcAKEKeys(t *testing.T) {
 }
 
 func Test_generateRevealKeyEncryptedSignature(t *testing.T) {
-	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"cbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
 	c := newConversation(otrV3{}, rnd)
 	c.initAKE()
 
@@ -395,7 +406,12 @@ func Test_generateRevealKeyEncryptedSignature(t *testing.T) {
 }
 
 func Test_generateSigKeyEncryptedSignature(t *testing.T) {
-	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"})
+	rnd := fixedRand([]string{"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+		"bbcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+	})
 	c := newConversation(otrV3{}, rnd)
 	c.initAKE()
 
diff --git a/debian/changelog b/debian/changelog
index 486179e..7c45b5d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+golang-github-twstrike-otr3 (0.0~git20161015.0.744856d-3.1) unstable; urgency=medium
+
+  * Non maintainer upload by the Reproducible Builds team.
+  * No source change upload to rebuild on buildd with .buildinfo files.
+
+ -- Holger Levsen <holger@debian.org>  Sat, 09 Jan 2021 17:01:32 +0100
+
 golang-github-twstrike-otr3 (0.0~git20161015.0.744856d-3) unstable; urgency=medium
 
   * Add patch from upstream to fix builds with Go 1.11.
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..b4de394
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+11
diff --git a/debian/control b/debian/control
index f146592..a8f55f9 100644
--- a/debian/control
+++ b/debian/control
@@ -3,7 +3,7 @@ Maintainer: Debian Go Packaging Team <pkg-go-maintainers@lists.alioth.debian.org
 Uploaders: Sascha Steinbiss <satta@debian.org>
 Section: devel
 Priority: optional
-Build-Depends: debhelper-compat (= 12),
+Build-Depends: debhelper (>= 11),
                dh-golang,
                golang-go
 Standards-Version: 4.1.4
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
index 594e14e..5c8c31b 100644
--- a/debian/gitlab-ci.yml
+++ b/debian/gitlab-ci.yml
@@ -1,6 +1,28 @@
+
 # auto-generated, DO NOT MODIFY.
 # The authoritative copy of this file lives at:
-# https://salsa.debian.org/go-team/infra/pkg-go-tools/blob/master/config/gitlabciyml.go
----
-include:
-  - https://salsa.debian.org/go-team/infra/pkg-go-tools/-/raw/master/pipeline/test-archive.yml
+# https://salsa.debian.org/go-team/ci/blob/master/cmd/ci/gitlabciyml.go
+
+# TODO: publish under debian-go-team/ci
+image: stapelberg/ci2
+
+test_the_archive:
+  artifacts:
+    paths:
+    - before-applying-commit.json
+    - after-applying-commit.json
+  script:
+    # Create an overlay to discard writes to /srv/gopath/src after the build:
+    - "rm -rf /cache/overlay/{upper,work}"
+    - "mkdir -p /cache/overlay/{upper,work}"
+    - "mount -t overlay overlay -o lowerdir=/srv/gopath/src,upperdir=/cache/overlay/upper,workdir=/cache/overlay/work /srv/gopath/src"
+    - "export GOPATH=/srv/gopath"
+    - "export GOCACHE=/cache/go"
+    # Build the world as-is:
+    - "ci-build -exemptions=/var/lib/ci-build/exemptions.json > before-applying-commit.json"
+    # Copy this package into the overlay:
+    - "GBP_CONF_FILES=:debian/gbp.conf gbp buildpackage --git-no-pristine-tar --git-ignore-branch --git-ignore-new --git-export-dir=/tmp/export --git-no-overlay --git-tarball-dir=/nonexistant --git-cleaner=/bin/true --git-builder='dpkg-buildpackage -S -d --no-sign'"
+    - "pgt-gopath -dsc /tmp/export/*.dsc"
+    # Rebuild the world:
+    - "ci-build -exemptions=/var/lib/ci-build/exemptions.json > after-applying-commit.json"
+    - "ci-diff before-applying-commit.json after-applying-commit.json"
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
deleted file mode 100644
index efefa27..0000000
--- a/debian/upstream/metadata
+++ /dev/null
@@ -1,4 +0,0 @@
-Bug-Database: https://github.com/twstrike/otr3/issues
-Bug-Submit: https://github.com/twstrike/otr3/issues/new
-Repository: https://github.com/twstrike/otr3.git
-Repository-Browse: https://github.com/twstrike/otr3
diff --git a/keys_test.go b/keys_test.go
index 04c8eaf..7ffbeb5 100644
--- a/keys_test.go
+++ b/keys_test.go
@@ -979,13 +979,13 @@ func Test_ImportKeysFromFile_willReturnAnErrorIfAskedToReadAFileNameThatDoesntEx
 }
 
 func Test_ImportKeysFromFile_willReturnAValidAccountReadFromAFile(t *testing.T) {
-	res, err := ImportKeysFromFile("test_resources/valid_key.asc")
+	res, err := ImportKeysFromFile("/tmp/valid_key.asc")
 	assertDeepEquals(t, len(res), 1)
 	assertDeepEquals(t, err, nil)
 }
 
 func Test_ImportKeysFromFile_willReturnAnErrorIfTheFileIsinvalid(t *testing.T) {
-	_, err := ImportKeysFromFile("test_resources/invalid_key.asc")
+	_, err := ImportKeysFromFile("/tmp/invalid_key.asc")
 	assertDeepEquals(t, err, newOtrError("couldn't import data into private key"))
 }
 
@@ -1061,12 +1061,12 @@ func Test_ExportKeysToFile_exportsKeysToAFile(t *testing.T) {
 	priv.Parse(serializedPrivateKey)
 	acc := &Account{Name: "hello", Protocol: "go-xmpp", Key: priv}
 
-	err := ExportKeysToFile([]*Account{acc}, "test_resources/test_export_of_keys.blah")
+	err := ExportKeysToFile([]*Account{acc}, "/tmp/test_export_of_keys.blah")
 	assertNil(t, err)
 
-	res, err2 := ImportKeysFromFile("test_resources/test_export_of_keys.blah")
+	res, err2 := ImportKeysFromFile("/tmp/test_export_of_keys.blah")
 
-	defer os.Remove("test_resources/test_export_of_keys.blah")
+	defer os.Remove("/tmp/test_export_of_keys.blah")
 
 	assertNil(t, err2)
 	assertDeepEquals(t, res[0].Key, acc.Key)

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

Run locally

More details

Full run details