Edits for bridge (#22)

* Edits for bridge

* Add keyring method to extract first key, improve docs
This commit is contained in:
wussler 2019-08-29 17:45:13 +02:00 committed by GitHub
parent 4ef79f1d12
commit 72e33612c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 217 additions and 40 deletions

View file

@ -332,11 +332,7 @@ No change.
No change.
### UnmarshalJSON
Renamed.
```
(kr *KeyRing) UnmarshalJSON(b []byte) (err error):
* (keyRing *KeyRing) ReadFromJSON(jsonData []byte) (err error)
```
No change.
### Identities
No change

View file

@ -309,3 +309,22 @@ var verifyTime = pgp.GetUnixTime()
verifiedPlainText, err := VerifyCleartextMessageArmored(publicKey, armored, verifyTime)
```
### Encrypting and decrypting session Keys
```go
// Keys initialization as before (omitted)
symmetricKey := &SymmetricKey{
Key: "RandomTokenabcdef",
Algo: constants.AES256,
}
keyPacket, err := publicKey.EncryptSessionKey(symmetricKey)
```
`KeyPacket` is a `[]byte` containing the session key encrypted with the private key.
```go
outputSymmetricKey, err := privateKey.DecryptSessionKey(keyPacket)
```
`outputSymmetricKey` is an object of type `*SymmetricKey` that can be used to decrypt the correspondig message.

View file

@ -88,7 +88,8 @@ func (keyRing *KeyRing) newAttachmentProcessor(
}
// EncryptAttachment encrypts a file given a PlainMessage and a fileName.
// Returns a PGPSplitMessage containing a session key packet and symmetrically encrypted data
// Returns a PGPSplitMessage containing a session key packet and symmetrically encrypted data.
// Specifically designed for attachments rather than text messages.
func (keyRing *KeyRing) EncryptAttachment(message *PlainMessage, fileName string) (*PGPSplitMessage, error) {
ap, err := keyRing.newAttachmentProcessor(len(message.GetBinary()), fileName, -1)
if err != nil {
@ -114,6 +115,7 @@ func (keyRing *KeyRing) NewLowMemoryAttachmentProcessor(
// DecryptAttachment takes a PGPSplitMessage, containing a session key packet and symmetrically encrypted data
// and returns a decrypted PlainMessage
// Specifically designed for attachments rather than text messages.
func (keyRing *KeyRing) DecryptAttachment(message *PGPSplitMessage) (*PlainMessage, error) {
privKeyEntries := keyRing.entities

View file

@ -64,7 +64,7 @@ func TestAttachmentEncrypt(t *testing.T) {
t.Fatal("Expected no error while encrypting attachment, got:", err)
}
pgpMessage := NewPGPMessage(append(encSplit.GetBinaryKeyPacket(), encSplit.GetBinaryDataPacket()...))
pgpMessage := NewPGPMessage(encSplit.GetBinary())
redecData, err := testPrivateKeyRing.Decrypt(pgpMessage, nil, 0)
if err != nil {

View file

@ -286,8 +286,8 @@ func (pgp *GopenPGP) BuildKeyRingArmored(key string) (keyRing *KeyRing, err erro
return &KeyRing{entities: keyEntries}, err
}
// ReadFromJSON reads multiple keys from a json array and fills the keyring
func (keyRing *KeyRing) ReadFromJSON(jsonData []byte) (err error) {
// UnmarshalJSON reads multiple keys from a json array and fills the keyring
func (keyRing *KeyRing) UnmarshalJSON(jsonData []byte) (err error) {
keyObjs, err := unmarshalJSON(jsonData)
if err != nil {
return err
@ -301,6 +301,10 @@ func (keyRing *KeyRing) ReadFromJSON(jsonData []byte) (err error) {
// If the token is not available it will fall back to just reading the keys, and leave them locked.
func (keyRing *KeyRing) UnlockJSONKeyRing(jsonData []byte) (newKeyRing *KeyRing, err error) {
keyObjs, err := unmarshalJSON(jsonData)
if err != nil {
return nil, err
}
newKeyRing = &KeyRing{}
err = newKeyRing.newKeyRingFromPGPKeyObject(keyObjs)
if err != nil {
@ -356,17 +360,13 @@ func (keyRing *KeyRing) newKeyRingFromPGPKeyObject(keyObjs []pgpKeyObject) error
return nil
}
// unmarshalJSON implements encoding/json.Unmarshaler.
// unmarshalJSON decodes key json from the API
func unmarshalJSON(jsonData []byte) ([]pgpKeyObject, error) {
keyObjs := []pgpKeyObject{}
if err := json.Unmarshal(jsonData, &keyObjs); err != nil {
return nil, err
}
if len(keyObjs) == 0 {
return nil, errors.New("gopenpgp: no key found")
}
return keyObjs, nil
}
@ -447,3 +447,12 @@ func FilterExpiredKeys(contactKeys []*KeyRing) (filteredKeys []*KeyRing, err err
return filteredKeys, nil
}
// FirstKey returns a KeyRing with only the first key of the original one
func (keyRing *KeyRing) FirstKey() *KeyRing {
newKeyRing := &KeyRing{}
newKeyRing.FirstKeyID = keyRing.FirstKeyID
newKeyRing.entities = keyRing.entities[:1]
return newKeyRing;
}

View file

@ -12,8 +12,8 @@ import (
// Encrypt encrypts a PlainMessage, outputs a PGPMessage.
// If an unlocked private key is also provided it will also sign the message.
// message : The plaintext input as a PlainMessage
// privateKey : (optional) an unlocked private keyring to include signature in the message
// * message : The plaintext input as a PlainMessage
// * privateKey : (optional) an unlocked private keyring to include signature in the message
func (keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PGPMessage, error) {
encrypted, err := asymmetricEncrypt(message.GetBinary(), keyRing, privateKey, true)
if err != nil {
@ -24,9 +24,11 @@ func (keyRing *KeyRing) Encrypt(message *PlainMessage, privateKey *KeyRing) (*PG
}
// Decrypt decrypts encrypted string using pgp keys, returning a PlainMessage
// message : The encrypted input as a PGPMessage
// verifyKey : Public key for signature verification (optional)
// verifyTime : Time at verification (necessary only if verifyKey is not nil)
// * message : The encrypted input as a PGPMessage
// * verifyKey : Public key for signature verification (optional)
// * verifyTime : Time at verification (necessary only if verifyKey is not nil)
//
// When verifyKey is not provided, then verifyTime should be zero, and signature verification will be ignored
func (keyRing *KeyRing) Decrypt(
message *PGPMessage, verifyKey *KeyRing, verifyTime int64,
) (*PlainMessage, error) {

View file

@ -43,12 +43,12 @@ var testIdentity = &Identity{
func init() {
var err error
testPrivateKeyRing, err = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
testPrivateKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
if err != nil {
panic(err)
}
testPublicKeyRing, err = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_publicKey", false)))
testPublicKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_publicKey", false))
if err != nil {
panic(err)
}
@ -92,7 +92,7 @@ func TestKeyRing_ArmoredPublicKeyString(t *testing.T) {
}
func TestCheckPassphrase(t *testing.T) {
encryptedKeyRing, _ := ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
encryptedKeyRing, _ := pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
isCorrect := encryptedKeyRing.CheckPassphrase("Wrong password")
assert.Exactly(t, false, isCorrect)
@ -107,7 +107,7 @@ func TestIdentities(t *testing.T) {
}
func TestFilterExpiredKeys(t *testing.T) {
expiredKey, _ := ReadArmoredKeyRing(strings.NewReader(readTestFile("key_expiredKey", false)))
expiredKey, _ := pgp.BuildKeyRingArmored(readTestFile("key_expiredKey", false))
keys := []*KeyRing{testPrivateKeyRing, expiredKey}
unexpired, err := FilterExpiredKeys(keys)
@ -149,9 +149,9 @@ func TestKeyIds(t *testing.T) {
assert.Exactly(t, assertKeyIDs, keyIDs)
}
func TestReadFromJson(t *testing.T) {
func TestUnmarshalJSON(t *testing.T) {
decodedKeyRing := &KeyRing{}
err = decodedKeyRing.ReadFromJSON([]byte(readTestFile("keyring_jsonKeys", false)))
err = decodedKeyRing.UnmarshalJSON([]byte(readTestFile("keyring_jsonKeys", false)))
if err != nil {
t.Fatal("Expected no error while reading JSON, got:", err)
}
@ -165,14 +165,14 @@ func TestReadFromJson(t *testing.T) {
}
func TestUnlockJson(t *testing.T) {
userKeyRing, err := ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_userKey", false)))
userKeyRing, err := pgp.BuildKeyRingArmored(readTestFile("keyring_userKey", false))
if err != nil {
t.Fatal("Expected no error while creating keyring, got:", err)
}
err = userKeyRing.UnlockWithPassphrase("testpassphrase")
if err != nil {
t.Fatal("Expected no error while creating keyring, got:", err)
t.Fatal("Expected no error while decrypting keyring, got:", err)
}
addressKeyRing, err := userKeyRing.UnlockJSONKeyRing([]byte(readTestFile("keyring_newJSONKeys", false)))
@ -183,4 +183,38 @@ func TestUnlockJson(t *testing.T) {
for _, e := range addressKeyRing.entities {
assert.Exactly(t, false, e.PrivateKey.Encrypted)
}
addressKeyRing, err = userKeyRing.UnlockJSONKeyRing([]byte(readTestFile("keyring_jsonKeys", false)))
if err != nil {
t.Fatal("Expected no error while reading and decrypting JSON, got:", err)
}
for _, e := range addressKeyRing.entities {
assert.Exactly(t, true, e.PrivateKey.Encrypted)
}
}
func TestMutlipleKeyRing(t *testing.T) {
testPublicKeyRing, _ = pgp.BuildKeyRingArmored(readTestFile("keyring_publicKey", false))
assert.Exactly(t, 1, len(testPublicKeyRing.entities))
ids := testPublicKeyRing.KeyIds()
assert.Exactly(t, uint64(0x3eb6259edf21df24), ids[0])
err = testPublicKeyRing.readFrom(strings.NewReader(readTestFile("mime_publicKey", false)), true)
if err != nil {
t.Fatal("Expected no error while adding a key to the keyring, got:", err)
}
assert.Exactly(t, 2, len(testPublicKeyRing.entities))
ids = testPublicKeyRing.KeyIds()
assert.Exactly(t, uint64(0x3eb6259edf21df24), ids[0])
assert.Exactly(t, uint64(0x374130b32ee1e5ea), ids[1])
singleKey := testPublicKeyRing.FirstKey()
assert.Exactly(t, 1, len(singleKey.entities))
ids = singleKey.KeyIds()
assert.Exactly(t, uint64(0x3eb6259edf21df24), ids[0])
}

View file

@ -20,7 +20,7 @@ import (
// ---- MODELS -----
// PlainMessage stores an unencrypted message.
// PlainMessage stores a plain text / unencrypted message.
type PlainMessage struct {
// The content of the message
Data []byte
@ -47,7 +47,9 @@ type PGPSplitMessage struct {
KeyPacket []byte
}
// ClearTextMessage, split signed clear text message container
// ClearTextMessage, split signed clear text message container.
// A Cleartext message is a signed PGP message, that is not encrypted,
// i.e. the ones beginning with -----BEGIN PGP SIGNED MESSAGE-----
type ClearTextMessage struct {
Data []byte
Signature []byte
@ -153,7 +155,7 @@ func NewClearTextMessage(data []byte, signature []byte) *ClearTextMessage {
func NewClearTextMessageFromArmored(signedMessage string) (*ClearTextMessage, error) {
modulusBlock, rest := clearsign.Decode([]byte(signedMessage))
if len(rest) != 0 {
return nil, errors.New("pmapi: extra data after modulus")
return nil, errors.New("gopenpgp: extra data after modulus")
}
signature, err := ioutil.ReadAll(modulusBlock.ArmoredSignature.Body)
@ -221,7 +223,19 @@ func (msg *PGPSplitMessage) GetBinaryKeyPacket() []byte {
return msg.KeyPacket
}
// GetBinary returns the unarmored binary joined packets as a []byte
func (msg *PGPSplitMessage) GetBinary() []byte {
return append(msg.KeyPacket , msg.DataPacket...)
}
// GetArmored returns the armored message as a string, with joined data and key packets
func (msg *PGPSplitMessage) GetArmored() (string, error) {
return armor.ArmorWithType(msg.GetBinary(), constants.PGPMessageHeader)
}
// SeparateKeyAndData returns the first keypacket and the (hopefully unique) dataPacket (not verified)
// * estimatedLength is the estimate length of the message
// * garbageCollector > 0 activates the garbage collector
func (msg *PGPMessage) SeparateKeyAndData(estimatedLength, garbageCollector int) (outSplit *PGPSplitMessage, err error) {
// For info on each, see: https://golang.org/pkg/runtime/#MemStats
packets := packet.NewReader(bytes.NewReader(msg.Data))

View file

@ -1,11 +1,14 @@
package crypto
import (
"bytes"
"encoding/base64"
"io"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/openpgp/packet"
)
func TestTextMessageEncryptionWithSymmetricKey(t *testing.T) {
@ -52,8 +55,8 @@ func TestBinaryMessageEncryptionWithSymmetricKey(t *testing.T) {
func TestTextMessageEncryption(t *testing.T) {
var message = NewPlainMessageFromString("plain text")
testPublicKeyRing, _ = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_publicKey", false)))
testPrivateKeyRing, err = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
testPublicKeyRing, _ = pgp.BuildKeyRingArmored(readTestFile("keyring_publicKey", false))
testPrivateKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
// Password defined in keyring_test
err = testPrivateKeyRing.UnlockWithPassphrase(testMailboxPassword)
@ -77,8 +80,8 @@ func TestBinaryMessageEncryption(t *testing.T) {
binData, _ := base64.StdEncoding.DecodeString("ExXmnSiQ2QCey20YLH6qlLhkY3xnIBC1AwlIXwK/HvY=")
var message = NewPlainMessage(binData)
testPublicKeyRing, _ = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_publicKey", false)))
testPrivateKeyRing, err = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
testPublicKeyRing, _ = pgp.BuildKeyRingArmored(readTestFile("keyring_publicKey", false))
testPrivateKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
// Password defined in keyring_test
err = testPrivateKeyRing.UnlockWithPassphrase(testMailboxPassword)
@ -96,6 +99,13 @@ func TestBinaryMessageEncryption(t *testing.T) {
t.Fatal("Expected no error when decrypting, got:", err)
}
assert.Exactly(t, message.GetBinary(), decrypted.GetBinary())
// Decrypt without verifying
decrypted, err = testPrivateKeyRing.Decrypt(ciphertext, nil, 0)
if err != nil {
t.Fatal("Expected no error when decrypting, got:", err)
}
assert.Exactly(t, message.GetString(), decrypted.GetString())
}
func TestIssue11(t *testing.T) {
@ -128,3 +138,70 @@ func TestIssue11(t *testing.T) {
assert.Exactly(t, "message from sender", plainMessage.GetString())
}
func TestSignedMessageDecryption(t *testing.T) {
testPrivateKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
// Password defined in keyring_test
err = testPrivateKeyRing.UnlockWithPassphrase(testMailboxPassword)
if err != nil {
t.Fatal("Expected no error unlocking privateKey, got:", err)
}
pgpMessage, err := NewPGPMessageFromArmored(readTestFile("message_signed", false))
if err != nil {
t.Fatal("Expected no error when unarmoring, got:", err)
}
decrypted, err := testPrivateKeyRing.Decrypt(pgpMessage, nil, 0)
if err != nil {
t.Fatal("Expected no error when decrypting, got:", err)
}
assert.Exactly(t, readTestFile("message_plaintext", true), decrypted.GetString())
}
func TestMultipleKeyMessageEncryption(t *testing.T) {
var message = NewPlainMessageFromString("plain text")
testPublicKeyRing, _ = pgp.BuildKeyRingArmored(readTestFile("keyring_publicKey", false))
err = testPublicKeyRing.readFrom(strings.NewReader(readTestFile("mime_publicKey", false)), true)
if err != nil {
t.Fatal("Expected no error adding second public key, got:", err)
}
assert.Exactly(t, 2, len(testPublicKeyRing.entities))
testPrivateKeyRing, err = pgp.BuildKeyRingArmored(readTestFile("keyring_privateKey", false))
// Password defined in keyring_test
err = testPrivateKeyRing.UnlockWithPassphrase(testMailboxPassword)
if err != nil {
t.Fatal("Expected no error unlocking privateKey, got:", err)
}
ciphertext, err := testPublicKeyRing.Encrypt(message, testPrivateKeyRing)
if err != nil {
t.Fatal("Expected no error when encrypting, got:", err)
}
numKeyPackets := 0
packets := packet.NewReader(bytes.NewReader(ciphertext.Data))
for {
var p packet.Packet
if p, err = packets.Next(); err == io.EOF {
err = nil
break
}
switch p.(type) {
case *packet.EncryptedKey:
numKeyPackets++
}
}
assert.Exactly(t, 2, numKeyPackets)
decrypted, err := testPrivateKeyRing.Decrypt(ciphertext, testPublicKeyRing, pgp.GetUnixTime())
if err != nil {
t.Fatal("Expected no error when decrypting, got:", err)
}
assert.Exactly(t, message.GetString(), decrypted.GetString())
}

View file

@ -74,8 +74,8 @@ func newSymmetricKeyFromEncrypted(ek *packet.EncryptedKey) (*SymmetricKey, error
}
// Encrypt encrypts a PlainMessage to PGPMessage with a SymmetricKey
// message : The plain data as a PlainMessage
// output : The encrypted data as PGPMessage
// * message : The plain data as a PlainMessage
// * output : The encrypted data as PGPMessage
func (symmetricKey *SymmetricKey) Encrypt(message *PlainMessage) (*PGPMessage, error) {
encrypted, err := symmetricEncrypt(message.GetBinary(), symmetricKey)
if err != nil {
@ -86,8 +86,8 @@ func (symmetricKey *SymmetricKey) Encrypt(message *PlainMessage) (*PGPMessage, e
}
// Decrypt decrypts password protected pgp binary messages
// encrypted: PGPMessage
// output: PlainMessage
// * encrypted: PGPMessage
// * output: PlainMessage
func (symmetricKey *SymmetricKey) Decrypt(message *PGPMessage) (*PlainMessage, error) {
decrypted, err := symmetricDecrypt(message.NewReader(), symmetricKey)
if err != nil {

View file

@ -6,7 +6,8 @@
"Version": 3,
"Activation": null,
"PrivateKey": "-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: ProtonMail\nComment: https://protonmail.com\n\n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\nSmpbVZj1NSvPN4xFOnZaytD99Yt/8ZFonY9Rjg==\n=5ACd\n-----END PGP PRIVATE KEY BLOCK-----\n",
"Token": null
"Token": null,
"Signature": null
},
{
"ID": "88xeHAObMEZp8b15R3643qJFbRoAXPm-FNuHxWO_VBVEqm294wuKCbIdoytQwHq2uwTxAXB-c4Jh0R47F34qig==",
@ -15,6 +16,7 @@
"Version": 3,
"Activation": null,
"PrivateKey": "-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: ProtonMail\nComment: https://protonmail.com\n\nxYYEXMcTAxYJKwYBBAHaRw8BAQdAjYhUufSrYtCsWhJMjCaEkdJb1Zuauh8P\nS0WipcZO2dD+CQMIxbf+ePNBNFVgXUTPHWmy2PpBS2FHQWgONx0UQLRi+JyT\nMJmxS/CToS54Eo0sWEjaZROZr8f5smCgBZqZsRWv4CA35qBG/RxJMkVH2lKQ\nuM0zZWxlY3Ryb25AcHJvdG9ubWFpbC5ibHVlIDxlbGVjdHJvbkBwcm90b25t\nYWlsLmJsdWU+wncEEBYKAB8FAlzaAdIGCwkHCAMCBBUICgIDFgIBAhkBAhsD\nAh4BAAoJEP7+7R3IrxGwxh0BAKbR76lG0OH83tI5quvyNf7yt+ck/uV8MrPZ\ntcBLHwO3AQCd5CHU3Rx7Huw0QsVkJYr7t3JEYfSaTK2wTxUFKudSDceLBFzH\nEwMSCisGAQQBl1UBBQEBB0Dijq86qjP8AEv98lTBqw69HAAxo0S4Eqh1P4qU\n1irhLwMBCAf+CQMIXvD746WZtFtglCNKwMqcHMFJ0sadSDo6ntYdiQwSM42E\n0jdfdM+JUIfDw9cOXflCcdW8yUJSRaBL1BXwtCcr686pkPZ/79qxuqYY6+Nq\nzMJhBBgWCAAJBQJc2gHSAhsMAAoJEP7+7R3IrxGwKzUA/j/00OybZkE3oTDO\n2fLjBZtlKa7T1n4+vZb+T8dvl2wnAP9Ln3wTzY9oXN/n/WgSi8Q5iT2to7zx\n25aU/PlFqHQmBQ==\n=3PyZ\n-----END PGP PRIVATE KEY BLOCK-----\n",
"Token": null
"Token": null,
"Signature": null
}
]

1
crypto/testdata/message_plaintext vendored Normal file
View file

@ -0,0 +1 @@
<div>jeej saas<br></div><div><br></div><div class="protonmail_signature_block"><div>Sent from <a href="https://protonmail.ch">ProtonMail</a>, encrypted email based in Switzerland.<br></div><div><br></div></div>

21
crypto/testdata/message_signed vendored Normal file
View file

@ -0,0 +1,21 @@
-----BEGIN PGP MESSAGE-----
Version: OpenPGP.js v4.5.3
Comment: https://openpgpjs.org
wcBMA0fcZ7XLgmf2AQgAgnHOlcAwVu2AnVfi2fIQHSkTQ0OFnZMJMRR3MJ1q
HtUW8jkSLcurL0Sn/tBFLIIR4YT2tQMzV7cvZzZyBEuZM4OYnDp8xSmoszPh
Gc/nvYG0A0pmKAQkL27v05Dul8oUWA0APT51urghH2Pzm7NdOMtTKIE4LQjS
mBfQ6Cf14uKV0xGS9v2dSFjFxxXEEpMQ+k60NCKRYClN2LVVxf3OKXbuugds
m2GUGn3CuFsiabosIUv4EcdE3aD9HbNo+PIWLJWRJIYJSc5+FWcbwXuIIFgC
XX1s7OV53ceZJnhjCmDE0N2ZOLLAYWED2zRvUa+CAqG+hZgc/3Ia+UmJUVuZ
BNLAugFuRsOVgh3olUIz0vazHhyGG0XIsNqmRm0U9SIfhWkPPHBmU6Xht6Qw
EvLbBfKTYHxX01yQUNgIv4S/TULeQuUjZQfsNYNXXGepS+jiCoIdEgUwpvre
OMFGsypwQXVCFYO/GQdYanMQRTckEexyBY4hGYVrevDM1yG/zGJIdbfI2L+1
1cz76jI8PtzL+S0zcVkevLcjjsHm2Je959uSida9jara7Bymr0y56UdoXoWX
4vZ0kQNo58eEEV0zg7dit4lDvwcuSZMW6K//xNtRQ4QX7/EDtlcYqBJXPwJY
eQSBVeYbeUbZ+PHJdu5gbI85BJNE2dKcS1bdOhEU2lPLYpvmMpPdot9TwnJb
dN3l8yDyhScGvTIZqlxhU7HCM9VHAS0bDqCUoO8EruztUSgjMI+gKC9+xdVU
yrkF7K23UNLWflROMv4cp0LDRB57619Y2w5lY/MG5bS0jSfMWBwnJG2AF28c
2tYKnHw6rpZXvXnlDmEDT8suTzuTGA==
=Sir8
-----END PGP MESSAGE-----