Commit d41b4df7 authored by Lukas Matt's avatar Lukas Matt

Clean up EncryptedMagicEnvelope

parent 43eb17fb
......@@ -19,10 +19,10 @@ package federation
import (
"bytes"
"io"
"encoding/base64"
"crypto/aes"
"crypto/cipher"
"io"
"crypto/rand"
)
......@@ -63,15 +63,9 @@ func (a *Aes) Encrypt(data []byte) error {
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2.
if len(data)%aes.BlockSize != 0 {
paddingLen := aes.BlockSize - (len(data)%aes.BlockSize)
paddingText := bytes.Repeat([]byte{byte(paddingLen)}, paddingLen)
//for i := 0; i < paddingLen; i++ {
// data = append(data, 0x20)
//}
data = append(data, paddingText...)
}
padding := aes.BlockSize - len(data)%aes.BlockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
data = append(data, padtext...)
key, err := base64.StdEncoding.DecodeString(a.Key)
if err != nil {
......@@ -91,7 +85,7 @@ func (a *Aes) Encrypt(data []byte) error {
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[:], data)
mode.CryptBlocks(ciphertext, data)
a.Data = base64.StdEncoding.EncodeToString(ciphertext)
return nil
......
......@@ -100,6 +100,8 @@ func (request *DiasporaUnmarshal) VerifySignature(serialized []byte) error {
}
func AuthorSignature(data interface{}, privKey string) (string, error) {
// XXX the order should be tracked in the database
// otherwise this can break stuff very quickly
var text string
switch entity := data.(type) {
case *EntityComment:
......@@ -113,24 +115,26 @@ func AuthorSignature(data interface{}, privKey string) (string, error) {
// positive guid parent_guid parent_type author
text = positive+";"+entity.Guid+";"+entity.ParentGuid+
";"+entity.TargetType+";"+entity.DiasporaHandle
default:
panic("Not supported interface type for AuthorSignature!")
}
return Sign(text, privKey)
}
func (d *PrivateEnvMarshal) Sign(privKey string) (err error) {
func (envelope *MagicEnvelopeMarshal) Sign(privKey string) (err error) {
type64 := base64.StdEncoding.EncodeToString(
[]byte(d.Data.Type),
[]byte(envelope.Data.Type),
)
encoding64 := base64.StdEncoding.EncodeToString(
[]byte(d.Encoding),
[]byte(envelope.Encoding),
)
alg64 := base64.StdEncoding.EncodeToString(
[]byte(d.Alg),
[]byte(envelope.Alg),
)
text := d.Data.Data + "." + type64 +
text := envelope.Data.Data + "." + type64 +
"." + encoding64 + "." + alg64
(*d).Sig.Sig, err = Sign(text, privKey)
(*envelope).Sig.Sig, err = Sign(text, privKey)
return
}
......
......@@ -19,88 +19,6 @@ package federation
import "encoding/xml"
/* Header
<?xml version="1.0" encoding="UTF-8"?>
<diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env">
<header>
<author_id>dia@192.168.0.173:3000</author_id>
</header>
*/
type Header struct {
XMLName xml.Name `xml:"header"`
AuthorId string `xml:"author_id"`
}
/* Encrypted Header
<?xml version="1.0" encoding="UTF-8"?>
<decrypted_header>
<iv>...</iv>
<aes_key>...</aes_key>
<author_id>one@two.tld</author_id>
</decrypted_header>
*/
// XXX legacy?
type XmlDecryptedHeader struct {
XMLName xml.Name `xml:"decrypted_header"`
Iv string `xml:"iv"`
AesKey string `xml:"aes_key"`
AuthorId string `xml:"author_id"`
}
type JsonEnvHeader struct {
AesKey string `json:"aes_key"`
Ciphertext string `json:"ciphertext"`
}
// Private Request
//
// <?xml version="1.0" encoding="UTF-8"?>
// <diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env">
// <encrypted_header>eyJhZXNfa2V5IjoiVTFGbVZ5TE5CT0pyOWViZVpiMUxnSGQzMlJwMzNMa1ViZVRnY3BEaDluZHAyT2cyMUZNeHh2Mm9RUXp0eWxLVjZsOEkzR0wvQlEzcEQxbGNYbjFGQWlEVTBmTHJwRUZwUEJNc1AwT3MvdmhEZ3I3MDJvaWNkMUxFN0ZMZ3ZVc1VKRGxGOHdvTVZUaGtnTmNVWGlCNUZpajcvb1J4ZFZ1QlJxbVpCQ0VXLys4PSIsImNpcGhlcnRleHQiOiJveWhWVjR5bXJoTGxYRVU1WVcxQWdpK29sTkxRSDlvR2NPQnVBOG00a25FZ09GZnJoNzEwUi9XQloyQ1I3WVlMeEhuOEcvUWFyU1UraDFka0VHMGFhcS9FQ1RWQjFHOXNkT2lQMnZSRTRkY1JOclNqb3RINXBsV3F4QVBvNlBpRkdwNUJZcURoYnB2RUNYNFNpM3BTN2hyOTdyWUs3NTFyYnYvRjNwRERJNG13d2NoUFA3S21nN21yVXBCZTBEeXRqQk5xK0k3S2lxSVQrRmVTUUMxc0pQSmd4TVAxck1VcDB6cURpT2ZlR3U2RGVnVG5MRnd5WHM3WEhGQW1FN29iSlZJY2NxS3czNjNWcnBrWXE0N1BDRWc3R3p1bFVlOXA5eFhDN3dVRmNOak91RTVQV1NXU1h3cWM0K2EybHFuOCJ9</encrypted_header>
// <me:env>
// <me:data type="application/xml">WXRPc09JakFleHh0dW5rQytRallnSEg0a08zOGd3ZVQyVVg4NkppVVZzVlJlMFFHbExhSjBtbzBnRUVGSnQyc2pqRG5OOUFETk1nakJ6MThGVnJsRWNEcjBqUDJ2emZPRjlCVHVLNXlvRjZqQ3NIRlh5USt4L3RlMnUxN0xCSUlxSDk4OGNhL1BVLzE2NEhBL0plQU1sMEZCOFBnTTFzYW9qUUJaV3V1RW95Y25ONWVZTm9wRi9adElXU3AxOFVzL05RWG13cktiWVVYYXJpNitOSWo1RWVOdTJrYnJnN2FoWUdhRFJKMVFtcEdhL0pMNmVvMEM1ZHFkS2s1amgrNFU0dnA0ZVY5bkRPK0ZGSkhpd3pDWm84NWJkdUR4T0NRRURpa2QxeGE1OWl4NkZWMTYzQ0MvMXBqdmhTa3cvTjNOTGdHOUZjWExQZDRwdTYzQ2pkS1E4QlE2MTYrMEFGREV0bjF0RldqYU9DV0VXOW5ORzQrTmNVZ0ZKamM0dzZxU3Ruc00rSFdzS0hOTnpRZElRc1pXT3c2bzJUK3ZCOUZmeUY3T3NTNHhwYnF0OW5MZFM1Z0U1M1lFb3FXVmRzK3E1a2xYV3dXdjlBeHRGdlhIVWxyNEE9PQ==</me:data>
// <me:encoding>base64url</me:encoding>
// <me:alg>RSA-SHA256</me:alg>
// <me:sig>sJPN--TJ9IqVwhT_j9mNGrLF4yQvwXUQKo24cPLi5FVXl-tVpyEOxrUI1gwRJ5j5UkkqNJO8mLph2ravlxqt7PNhS9YAOTuo46nXWXyOJjP_ESxq3DaMrYqQt57PDnM29x5yQ0QATbSAs6XneHtxmVKzwKgi4ZpdQ3THFj_iWwac0BI3Or1okt9wLxxl3LTLO9vwfIZaeo-XDNT7JlIfSMZDv1xipjtbl-P0z0q4u2wYOLquvvDjRdI_9vStZK3EOmYARhDXhH0vcJNjVXYTuq16BtXsyfEW3WLBPH67t9Ef3c6cWqU3qPSS3-ddZY5VVq6pPpmtnHuBNzB5hZvZ8asMexc7S0V075ZG-7axUcwXkWKTwCZuxwZNm3VinQze4meWY6vWITtD6zHCguMIWZgxW5z7LGZ04j8_26NbBmZXV52-TFRJExi6H6kUmDb3GrYTlLTOziEUB9pl4NkCX_ghi-Pixbzg7zc_LD_cKXoUyj7iHRNfdfXLck9SOxXkmWAI7hNAswBgx1ngnH6AVyNSsFYVNF1jzc-uTwANfMQqjqq5_XCdE2Z2GFOvFJQ6JK4S-gAEpLygzeltbvYxuK_qqONA9cCTqoJlOxSgQY_lj7h6s__1EuyP9_-Fh4J9MWi9i118ndkmzaswOcxU_VfnHLDgbQbXD5B7zaS1c90=</me:sig>
// </me:env>
// </diaspora>
type PrivateEnvMarshal struct {
XMLName xml.Name `xml:"me:env"`
Me string `xml:"xmlns:me,attr"`
Data struct {
XMLName xml.Name `xml:"me:data"`
Type string `xml:"type,attr"`
Data string `xml:",chardata"`
}
Encoding string `xml:"me:encoding"`
Alg string `xml:"me:alg"`
Sig struct {
XMLName xml.Name `xml:"me:sig"`
Sig string `xml:",chardata"`
KeyId string `xml:"key_id,attr,omitempty"`
}
}
type PrivateMarshal struct {
XMLName xml.Name `xml:"diaspora"`
Xmlns string `xml:"xmlns,attr"`
XmlnsMe string `xml:"me,attr"`
EncryptedHeader string `xml:"encrypted_header,omitempty"`
Env PrivateEnvMarshal
}
type PublicMarshal struct {
XMLName xml.Name `xml:"diaspora"`
Xmlns string `xml:"xmlns,attr"`
XmlnsMe string `xml:"me,attr"`
Header Header
Env PrivateEnvMarshal
}
// NOTE I had huge problems with marshal
// and unmarshal with the same structs
// apperently namespaces in tags are a problem
......
......@@ -25,67 +25,37 @@ import(
"crypto/rand"
)
func (request *PrivateMarshal) EncryptHeader(authorId string, serializedPubKey []byte) (err error) {
// Generate the AES key before you start
// encrypting the plain header
var aesKeySet Aes
err = aesKeySet.Generate()
if err != nil {
return
}
// The actual header
//
// <decrypted_header>
// <iv>...</iv>
// <aes_key>...</aes_key>
// <author_id>one@two.tld</author_id>
// </decrypted_header>
decryptedHeader := XmlDecryptedHeader{
Iv: aesKeySet.Iv,
AesKey: aesKeySet.Key,
AuthorId: authorId,
}
decryptedHeaderXml, err := json.Marshal(decryptedHeader)
if err != nil {
return err
}
err = aesKeySet.Encrypt(decryptedHeaderXml)
if err != nil {
return
}
aesKeySetXml, err := json.Marshal(aesKeySet)
if err != nil {
return err
}
pubKey, err := ParseRSAPubKey(serializedPubKey)
if err != nil {
return err
}
// aes_key
aesKey, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, aesKeySetXml)
if err != nil {
return err
}
aesKeyEncoded := base64.StdEncoding.EncodeToString(aesKey)
header := JsonEnvHeader{
AesKey: aesKeyEncoded,
Ciphertext: aesKeySet.Data,
}
headerXml, err := json.Marshal(header)
if err != nil {
return err
}
/* Header
<?xml version="1.0" encoding="UTF-8"?>
<diaspora xmlns="https://joindiaspora.com/protocol" xmlns:me="http://salmon-protocol.org/ns/magic-env">
<header>
<author_id>dia@192.168.0.173:3000</author_id>
</header>
*/
type Header struct {
XMLName xml.Name `xml:"header"`
AuthorId string `xml:"author_id"`
}
/* Decrypted Header
<?xml version="1.0" encoding="UTF-8"?>
<decrypted_header>
<iv>...</iv>
<aes_key>...</aes_key>
<author_id>one@two.tld</author_id>
</decrypted_header>
*/
type XmlDecryptedHeader struct {
XMLName xml.Name `xml:"decrypted_header"`
Iv string `xml:"iv"`
AesKey string `xml:"aes_key"`
AuthorId string `xml:"author_id"`
}
(*request).EncryptedHeader = base64.StdEncoding.EncodeToString(headerXml)
return
type JsonEnvHeader struct {
AesKey string `json:"aes_key"`
Ciphertext string `json:"ciphertext"`
}
func (request *DiasporaUnmarshal) DecryptHeader(serialized []byte) error {
......
......@@ -30,36 +30,38 @@ import (
const (
PROTO_HTTP = "http://"
PROTO_HTTPS = "https://"
CONTENT_TYPE_ENVELOPE = "application/magic-envelope+xml"
CONTENT_TYPE_JSON = "application/json"
CONTENT_TYPE_FORM = "application/x-www-form-urlencoded"
)
var timeout = time.Duration(10 * time.Second)
func PushXmlToPrivate(host, guid string, body io.Reader) error {
return pushXml(host, "/receive/users/" + guid, PROTO_HTTPS, body)
func PushJsonToPrivate(host, guid string, body io.Reader) error {
return push(host, "/receive/users/" + guid, PROTO_HTTPS, CONTENT_TYPE_JSON, body)
}
func PushXmlToPublic(host string, body io.Reader) error {
return pushXml(host, "/receive/public", PROTO_HTTPS, body)
return push(host, "/receive/public", PROTO_HTTPS, CONTENT_TYPE_ENVELOPE, body)
}
func pushXml(host, endpoint, proto string, body io.Reader) error {
func PushFormToPrivate(host, guid string, body io.Reader) error {
return push(host, "/receive/users/" + guid, PROTO_HTTPS, CONTENT_TYPE_FORM, body)
}
func push(host, endpoint, proto, contentType string, body io.Reader) error {
req, err := http.NewRequest("POST", proto + host + endpoint, body)
if err != nil {
return err
}
if strings.Contains(endpoint, "public") {
req.Header.Add("Content-Type", "application/magic-envelope+xml")
} else {
req.Header.Add("Content-Type", "application/json")
}
req.Header.Add("Content-Type", contentType)
client := &http.Client{Timeout: timeout}
resp, err := client.Do(req)
if err != nil {
if proto == PROTO_HTTPS {
info("Retry with", PROTO_HTTP, "on", host, err)
return pushXml(host, endpoint, PROTO_HTTP, body)
return push(host, endpoint, PROTO_HTTP, contentType, body)
}
return err
}
......
......@@ -20,13 +20,28 @@ package federation
import (
"encoding/base64"
"encoding/xml"
//XXX
"encoding/json"
"crypto/rsa"
"crypto/rand"
)
type MagicEnvelopeMarshal struct {
XMLName xml.Name `xml:"me:env"`
Me string `xml:"xmlns:me,attr"`
Data struct {
XMLName xml.Name `xml:"me:data"`
Type string `xml:"type,attr"`
Data string `xml:",chardata"`
}
Encoding string `xml:"me:encoding"`
Alg string `xml:"me:alg"`
Sig struct {
XMLName xml.Name `xml:"me:sig"`
Sig string `xml:",chardata"`
KeyId string `xml:"key_id,attr,omitempty"`
}
}
func MagicEnvelope(privkey, handle string, plainXml []byte) (payload []byte, err error) {
info("plain xml", string(plainXml))
info("privkey length", len(privkey))
......@@ -35,7 +50,7 @@ func MagicEnvelope(privkey, handle string, plainXml []byte) (payload []byte, err
data := base64.URLEncoding.EncodeToString(plainXml)
keyId := base64.URLEncoding.EncodeToString([]byte(handle))
xmlBody := PrivateEnvMarshal{}
xmlBody := MagicEnvelopeMarshal{}
xmlBody.Data.Type = APPLICATION_XML
xmlBody.Data.Data = data
xmlBody.Me = XMLNS_ME
......@@ -59,6 +74,9 @@ func MagicEnvelope(privkey, handle string, plainXml []byte) (payload []byte, err
}
func EncryptedMagicEnvelope(privkey, pubkey, handle string, serializedXml []byte) (payload []byte, err error) {
var aesKeySet Aes
var aesWrapper AesWrapper
info("serialized xml", string(serializedXml))
info("privkey length", len(privkey))
info("pubkey length", len(pubkey))
......@@ -67,58 +85,46 @@ func EncryptedMagicEnvelope(privkey, pubkey, handle string, serializedXml []byte
data := base64.URLEncoding.EncodeToString(serializedXml)
keyId := base64.URLEncoding.EncodeToString([]byte(handle))
// encrypted header
//xmlBody := PrivateMarshal{
// Xmlns: XMLNS,
// XmlnsMe: XMLNS_ME,
xmlBodyEnv := PrivateEnvMarshal{
envelope := MagicEnvelopeMarshal{
Me: XMLNS_ME,
Encoding: BASE64_URL,
Alg: RSA_SHA256,
}
//}
xmlBodyEnv.Data.Type = APPLICATION_XML
xmlBodyEnv.Data.Data = data
xmlBodyEnv.Sig.KeyId = keyId
envelope.Data.Type = APPLICATION_XML
envelope.Data.Data = data
envelope.Sig.KeyId = keyId
err = xmlBodyEnv.Sign(privkey)
err = envelope.Sign(privkey)
if err != nil {
warn(err)
return
}
// XXX NOTE move below to header file
// Generate a new AES key pair
var (
aesKeySet Aes
aesWrapper AesWrapper
)
err = aesKeySet.Generate()
if err != nil {
warn(err)
return
}
// payload mit aes versch und base64
payload, err = xml.Marshal(xmlBodyEnv)
// payload with aes encryption
payload, err = xml.Marshal(envelope)
if err != nil {
warn(err)
return
}
info("payload, err = xml.Marshal(envelope) ", string(payload))
err = aesKeySet.Encrypt(payload)
if err != nil {
warn(err)
return
}
//aesWrapper.MagicEnvelope = base64.StdEncoding.EncodeToString([]byte(aesKeySet.Data))
aesWrapper.MagicEnvelope = aesKeySet.Data
// aes mit pub key versch
// aes with rsa encryption
aesKeySetXml, err := json.Marshal(aesKeySet)
if err != nil {
warn(err)
......@@ -133,23 +139,19 @@ func EncryptedMagicEnvelope(privkey, pubkey, handle string, serializedXml []byte
info("aesKeySetXml", string(aesKeySetXml))
// aes_key
aesKey, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, aesKeySetXml)
if err != nil {
warn(err)
return
}
aesWrapper.AesKey = base64.StdEncoding.EncodeToString(aesKey)
payload, err = json.Marshal(aesWrapper)
if err != nil {
warn(err)
return
}
info("payload", string(payload))
return
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment