diff --git a/doc/fileformat.md b/doc/fileformat.md index 06881ad..051c887 100644 --- a/doc/fileformat.md +++ b/doc/fileformat.md @@ -34,7 +34,7 @@ else than a zip file containing the following shit. | | _________________________________________________________________________ | | - | | Envelop meta data: encryption type, mode, Paiload signature (yaml) + | | Envelop meta data: encryption type, mode, Paiload signature (yaml), IV,.. | |__________________________________________________________________________ | | __________________________________________________________________________ @@ -42,12 +42,12 @@ else than a zip file containing the following shit. | | Paiload: Zip file, no compression, symetrcally encrypted | | _____________________________________________________________________ | | | - | | | paiload intern metadata: Data signature, sender, message, IV, ... + | | | paiload intern metadata: Data signature, sender, message ... | | |______________________________________________________________________ | | | | _______________________________________________________________________ | | | - | | | Data: Zip file, high compression + | | | Data: Can be anything. But for file and folders, it will be zipped | | | | | | | | | diff --git a/helper/test_helper.go b/helper/test_helper.go index 8dfff8e..881eff1 100644 --- a/helper/test_helper.go +++ b/helper/test_helper.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/rsa" "encoding/binary" + "encoding/json" "io" "math/big" "math/rand" @@ -14,11 +15,12 @@ func B(x int64) *big.Int { } type MockRandomReader struct { - random *rand.Rand + readLength int + random *rand.Rand } func NewMockRandomReader() *MockRandomReader { - return &MockRandomReader{rand.New(rand.NewSource(99))} + return &MockRandomReader{0, rand.New(rand.NewSource(99))} } func (this *MockRandomReader) getNextFourRandomBytes() []byte { @@ -31,9 +33,14 @@ func (this *MockRandomReader) Read(p []byte) (n int, err error) { for i := 0; i < len(p); i += 4 { copy(p[i:], this.getNextFourRandomBytes()) } + this.readLength += len(p) return len(p), nil } +func (this *MockRandomReader) GetReadLength() int { + return this.readLength +} + func (this *MockRandomReader) GetRandomBytes(size int) []byte { ret := make([]byte, size) this.Read(ret) @@ -74,6 +81,17 @@ func (this *MockIoWriter) ReaderAt() io.ReaderAt { return bytes.NewReader(this.state) } +func (this *MockIoWriter) IsValidJson() bool { + m := make(map[string]interface{}) + l := make([]interface{}, 0, 100) + if json.Unmarshal(this.Bytes(), &m) == nil { + return true + } else if json.Unmarshal(this.Bytes(), &l) == nil { + return true + } + return false +} + func Range(length int) []byte { ret := make([]byte, length) for i, _ := range ret { diff --git a/helper/test_helper_test.go b/helper/test_helper_test.go index 8e0bdd9..09fa18a 100644 --- a/helper/test_helper_test.go +++ b/helper/test_helper_test.go @@ -43,6 +43,26 @@ func TestMockIoWriter(t *testing.T) { } } +func TestIsValidJson(t *testing.T) { + m := make(map[string]bool) + m[`{}`] = true + m[`[]`] = true + m[`[1, "abc", {"aa": true, "2": [1,2,3]}]`] = true + m[`{"aa": true, "2": [1,2,3]}`] = true + + m[`regular string`] = false + m[`{"aa": true "2": [1,2,3]}`] = false // malformed json + for json_, isJSON := range m { + w := &MockIoWriter{[]byte(json_)} + ok := w.IsValidJson() + if ok && !isJSON { + t.Error(json_, "is not json but has been detected as json") + } else if !ok && isJSON { + t.Error(json_, "is json but has not been detected as json") + } + } +} + func TestGetRSAPublicKeyAndGetRSAPrivateKey(t *testing.T) { privateKey := GetRSAPrivateKey(50) if err := privateKey.Validate(); err != nil { @@ -60,7 +80,7 @@ func TestGetRSAPublicKeyAndGetRSAPrivateKey(t *testing.T) { } func TestGetNextFourRandomBytes(t *testing.T) { - m := &MockRandomReader{rand.New(rand.NewSource(22))} + m := &MockRandomReader{0, rand.New(rand.NewSource(22))} rb := m.getNextFourRandomBytes() var expt []byte = []byte{233, 237, 107, 32} if len(rb) != 4 { @@ -103,3 +123,15 @@ func TestGetRandomBytes(t *testing.T) { t.Fail() } } + +func TestGetReadLength(t *testing.T) { + m := NewMockRandomReader() + dump := make([]byte, 4*10+3) + if _, err := m.Read(dump); err != nil { + t.Error(err) + return + } + if m.GetReadLength() != 4*10+3 { + t.Error("bad read length") + } +} diff --git a/payload/block.go b/payload/block.go index 594970a..a827107 100644 --- a/payload/block.go +++ b/payload/block.go @@ -36,11 +36,12 @@ func createRandomKey(lengthInBits int, rd io.Reader) ([]byte, error) { } } -func (this Block) CreateBlock(rd io.Reader) (cipher.Block, error) { +func (this Block) CreateBlock(rd io.Reader) (cipher.Block, []byte, error) { var err error key := make([]byte, 256/8) if _, err = rd.Read(key); err != nil { - return nil, err + return nil, nil, err } - return aes.NewCipher(key) + block, err := aes.NewCipher(key) + return block, key, err } diff --git a/payload/block_test.go b/payload/block_test.go index c0fc72f..bfdab5b 100644 --- a/payload/block_test.go +++ b/payload/block_test.go @@ -2,16 +2,42 @@ package payload import ( "crypto" + "crypto/aes" + "crypto/cipher" + "errors" + "fmt" "github.com/didiercrunch/ecrypto/helper" + "reflect" "testing" ) +type Blocker func([]byte) (cipher.Block, error) + +func assertBlockOkay(block cipher.Block, key []byte, blocker Blocker) error { + expectedBlock, err := blocker(key) + if err != nil { + return err + } + if expectedBlock.BlockSize() != block.BlockSize() { + return errors.New(fmt.Sprintf("bad block size. Expected %v but was %v", expectedBlock.BlockSize(), block.BlockSize())) + } + src := helper.Range(block.BlockSize()) + encrypt := make([]byte, block.BlockSize()) + decrypt := make([]byte, block.BlockSize()) + block.Encrypt(encrypt, src) + expectedBlock.Decrypt(decrypt, encrypt) + if !reflect.DeepEqual(decrypt, src) { + return errors.New("expected encryption is wrong") + } + return nil +} + func TestCreateBlock(t *testing.T) { random := helper.NewMockRandomReader() - if block, err := AES256.CreateBlock(random); err != nil { + if block, key, err := AES256.CreateBlock(random); err != nil { + t.Error(err) + } else if err := assertBlockOkay(block, key, aes.NewCipher); err != nil { t.Error(err) - } else { - _ = block } } @@ -19,11 +45,13 @@ func Testhash512BytesOfData(t *testing.T) { if _, err := hash512BytesOfData(crypto.MD5, helper.NewMockRandomReader()); err == nil { t.Error("should never allow MD5 hash") } - rd := helper.NewMockRandomReader() - if rd, err := hash512BytesOfData(crypto.SHA512, rd); err != nil { + randomGenerator := helper.NewMockRandomReader() + if rd, err := hash512BytesOfData(crypto.SHA512, randomGenerator); err != nil { t.Error(err) } else if len(rd) != 512/8 { t.Fail() + } else if l := randomGenerator.GetReadLength(); l != 512 { + t.Error(fmt.Sprint("Was suppose to read 512 bytes of data but read", l, "bytes of data")) } } diff --git a/payload/blockmode.go b/payload/blockmode.go new file mode 100644 index 0000000..34216ad --- /dev/null +++ b/payload/blockmode.go @@ -0,0 +1,45 @@ +package payload + +import ( + "crypto/cipher" + "errors" + "fmt" + "io" +) + +type BlockStream func(block cipher.Block, iv []byte) cipher.Stream + +type BlockMode string + +const OFB BlockMode = "ofb" + +func (this BlockMode) GetEncryptorStream() (BlockStream, error) { + switch this { + case OFB: + return cipher.NewOFB, nil + default: + err := fmt.Sprintf("BlockMode '%s' is not available", this) + return nil, errors.New(err) + } + +} + +func createIV(b cipher.Block, rd io.Reader) ([]byte, error) { + ret := make([]byte, b.BlockSize()) + if _, err := rd.Read(ret); err != nil { + return nil, err + } + return ret, nil +} + +func (this BlockMode) GetCipherStream(block cipher.Block, rd io.Reader) (stream cipher.Stream, iv []byte, err error) { + iv, err = createIV(block, rd) + if err != nil { + return nil, nil, err + } + streamCreator, err := this.GetEncryptorStream() + if err != nil { + return nil, nil, err + } + return streamCreator(block, iv), iv, nil +} diff --git a/payload/blockmode_test.go b/payload/blockmode_test.go new file mode 100644 index 0000000..61270eb --- /dev/null +++ b/payload/blockmode_test.go @@ -0,0 +1,48 @@ +package payload + +import ( + "crypto/cipher" + "crypto/des" + "github.com/didiercrunch/ecrypto/helper" + "testing" +) + +func getAnyBlock() cipher.Block { + block, err := des.NewTripleDESCipher(helper.Range(24)) + if err != nil { + panic(err) + } + return block +} + +func TestGetEncryptorStreamError(t *testing.T) { + var foo BlockMode = "some_shit" + if _, err := foo.GetEncryptorStream(); err == nil { + t.Error("should have an error here") + } else if err.Error() != "BlockMode 'some_shit' is not available" { + t.Error("bad error message") + } +} + +func TestOFB(t *testing.T) { + _, err := OFB.GetEncryptorStream() + if err != nil { + t.Error(err) + } +} + +func TestCreateIV(t *testing.T) { + block := getAnyBlock() + if iv, err := createIV(block, helper.NewMockRandomReader()); err != nil { + t.Error(err) + } else if len(iv) != block.BlockSize() { + t.Error("bad iv length") + } +} + +func TestGetCipherStream(t *testing.T) { + block := getAnyBlock() + if _, _, err := OFB.GetCipherStream(block, helper.NewMockRandomReader()); err != nil { + t.Error(err) + } +} diff --git a/payload/copy.go b/payload/copy.go new file mode 100644 index 0000000..9be2987 --- /dev/null +++ b/payload/copy.go @@ -0,0 +1,56 @@ +package payload + +import ( + "io" +) + +type CopyOutput struct { + Err error + Written int64 +} + +func copyAndUpdate(dst io.Writer, data []byte, copyOutput *CopyOutput) { + if copyOutput.Err != nil { + return + } + nw, ew := dst.Write(data) + if nw > 0 { + copyOutput.Written += int64(nw) + } + if ew != nil { + copyOutput.Err = ew + return + } + if len(data) != nw { + copyOutput.Err = io.ErrShortWrite + } +} + +func CopyToTwoWriters(dst1 io.Writer, dst2 io.Writer, src io.Reader) (copyOutput1 *CopyOutput, copyOutput2 *CopyOutput) { + // TODO: if necessary, implements the speedup methods if src implements *WriterTo* + // or if both dst implement ReaderFrom. See + // http://golang.org/src/pkg/io/io.go for example + copyOutput1, copyOutput2 = new(CopyOutput), new(CopyOutput) + var nr int + var er error + buf := make([]byte, 32*1024) + for { + nr, er = src.Read(buf) + if nr > 0 { + copyAndUpdate(dst1, buf[0:nr], copyOutput1) + copyAndUpdate(dst2, buf[0:nr], copyOutput2) + } + if copyOutput1.Err != nil && copyOutput2.Err != nil { + break + } + if er == io.EOF { + break + } + if er != nil { + copyOutput1.Err = er + copyOutput2.Err = er + break + } + } + return +} diff --git a/payload/copy_test.go b/payload/copy_test.go new file mode 100644 index 0000000..ed58654 --- /dev/null +++ b/payload/copy_test.go @@ -0,0 +1,29 @@ +package payload + +import ( + "bytes" + "io" + "testing" +) + +type Buffer struct { + bytes.Buffer + io.ReaderFrom // conflicts with and hides bytes.Buffer's ReaderFrom. + io.WriterTo // conflicts with and hides bytes.Buffer's WriterTo. +} + +// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN. + +func TestCopy(t *testing.T) { + rb := new(Buffer) + wb1 := new(Buffer) + wb2 := new(Buffer) + rb.WriteString("hello, world.") + CopyToTwoWriters(wb1, wb2, rb) + if wb1.String() != "hello, world." { + t.Errorf("Copy did not work properly") + } + if wb2.String() != "hello, world." { + t.Errorf("Copy did not work properly") + } +} diff --git a/payload/hash.go b/payload/hash.go new file mode 100644 index 0000000..073f2fc --- /dev/null +++ b/payload/hash.go @@ -0,0 +1,45 @@ +package payload + +import ( + cryptoSHA512 "crypto/sha512" + "errors" + "fmt" + "hash" + "io" +) + +type Hash string + +const SHA512 Hash = "sha512" + +func (this Hash) New() (hash.Hash, error) { + switch this { + case SHA512: + return cryptoSHA512.New(), nil + default: + msg := fmt.Sprintf("hash '%s' is not supported") + return nil, errors.New(msg) + } +} + +func (this Hash) HashOnTheWay(data io.Reader, resultingHash chan []byte) (io.Reader, error) { + h, err := this.New() + pipeReader, pipeWriter := io.Pipe() + if err != nil { + return nil, err + } + go func(resultingHash chan []byte) { + ou1, ou2 := CopyToTwoWriters(h, pipeWriter, data) + if ou1.Err != nil { + panic(ou1.Err) + } + if ou2.Err != nil { + panic(ou2.Err) + } + if err := pipeWriter.Close(); err != nil { + panic(err) + } + resultingHash <- h.Sum(nil) + }(resultingHash) + return pipeReader, nil +} diff --git a/payload/hash_test.go b/payload/hash_test.go new file mode 100644 index 0000000..5bbfb08 --- /dev/null +++ b/payload/hash_test.go @@ -0,0 +1,78 @@ +package payload + +import ( + "bytes" + cryptoSHA512 "crypto/sha512" + "encoding/hex" + "errors" + "github.com/didiercrunch/ecrypto/helper" + "hash" + "io" + "io/ioutil" + "reflect" + "testing" +) + +var __ = ioutil.Discard + +func TestUnsupportedHash(t *testing.T) { + unsupportedHashes := []Hash{"md5"} + for _, h := range unsupportedHashes { + if _, err := h.New(); err == nil { + t.Error("should have an error here") + } + } +} + +func assertHashIsOkay(h hash.Hash, expectedHash hash.Hash) error { + h.Reset() + expectedHash.Reset() + h.Write(helper.Range(1025)) + expectedHash.Write(helper.Range(1025)) + if !reflect.DeepEqual(h.Sum(nil), expectedHash.Sum(nil)) { + return errors.New("bad hash") + } + return nil +} + +func TestSHA512(t *testing.T) { + if h, err := SHA512.New(); err != nil { + t.Error(err) + return + } else if err = assertHashIsOkay(h, cryptoSHA512.New()); err != nil { + t.Error(err) + } +} + +func TestHashOnTheWay(t *testing.T) { + data := bytes.NewBufferString("some data to hash") + expectedHash, err := hex.DecodeString("c874e4001dbd67d770c47bc1bac090be069" + + "2ffcd5bb995de7df96a7100f05e061b85307657e6595d25ffd6931793892dd0215e64" + + "da97bb73c969b5fcfd2aed49") + _ = expectedHash + if err != nil { + t.Error(err) + return + } + outputHash := make(chan []byte) + var outputReader io.Reader + if outputReader, err = SHA512.HashOnTheWay(data, outputHash); err != nil { + t.Error(err) + } + errorC := make(chan error) + go func(errorC chan error) { + if output, err := ioutil.ReadAll(outputReader); err != nil { + errorC <- err + } else if string(output) != "some data to hash" { + errorC <- errors.New("output is not 'some data to hash' but: " + string(output)) + } + errorC <- nil + + }(errorC) + if err := <-errorC; err != nil { + t.Error(err) + } + if !reflect.DeepEqual(<-outputHash, expectedHash) { + t.Error("bad hash\nexpected: ", expectedHash, "\nreceived:", outputHash) + } +} diff --git a/payload/metadata.go b/payload/metadata.go new file mode 100644 index 0000000..6ea8f02 --- /dev/null +++ b/payload/metadata.go @@ -0,0 +1,37 @@ +package payload + +import ( + "encoding/hex" + "encoding/json" +) + +type Metadata struct { + IV []byte + Key []byte +} + +type jsonMetada struct { + IV string + Key string +} + +func (this *Metadata) MarshalJSON() ([]byte, error) { + ret := &jsonMetada{ + IV: hex.EncodeToString(this.IV), + Key: hex.EncodeToString(this.Key), + } + return json.Marshal(ret) +} + +func (this *Metadata) UnmarshalJSON(data []byte) (err error) { + ret := &jsonMetada{} + if err = json.Unmarshal(data, ret); err != nil { + return err + } + if this.IV, err = hex.DecodeString(ret.IV); err != nil { + return + } else if this.Key, err = hex.DecodeString(ret.Key); err != nil { + return + } + return +} diff --git a/payload/metadata_test.go b/payload/metadata_test.go new file mode 100644 index 0000000..fbc1236 --- /dev/null +++ b/payload/metadata_test.go @@ -0,0 +1,30 @@ +package payload + +import ( + "encoding/json" + "github.com/didiercrunch/ecrypto/helper" + "reflect" + "strings" + "testing" +) + +func TestJsonifyMetadata(t *testing.T) { + m := &Metadata{helper.Range(10), helper.Range(12)} + marshaled, err := json.Marshal(m) + if err != nil { + t.Error(err) + return + } + if !strings.Contains(string(marshaled), `"000102030405060708090a0b"`) { + t.Error(`marshaled data should containe "000102030405060708090a0b"`, "\n", string(marshaled)) + } + um := new(Metadata) + if err := json.Unmarshal(marshaled, um); err != nil { + t.Error(err) + return + } + if !reflect.DeepEqual(m, um) { + t.Error(m, " is not ", um) + } + +} diff --git a/payload/payload.go b/payload/payload.go index eb7f15c..350044e 100644 --- a/payload/payload.go +++ b/payload/payload.go @@ -1,84 +1,141 @@ package payload import ( - "crypto" + "archive/zip" "crypto/cipher" - "fmt" + "encoding/json" "io" ) -var _ = fmt.Print - -/* - type Payload interface { - GetHash() []byte - GetKey() []byte - GetAlgorithm() string - GetMode() string - GetHashMethod() string - GetPayloadData() io.Reader - } -*/ - -type BlockMode string - -const OFB BlockMode = "ofb" - type BlockModeStream func(block cipher.Block, iv []byte) cipher.Stream type Payload struct { DataSource io.Reader - Hash crypto.Hash + Random io.Reader + HashMethod Hash Block Block BlockMode BlockMode + + IV []byte + Key []byte + Hash []byte +} + +type payloadWriter struct { + Reader io.Reader + Pipewriter io.WriteCloser + ZipWriter *zip.Writer +} + +func getPayloadWriter() *payloadWriter { + p := new(payloadWriter) + p.Reader, p.Pipewriter = io.Pipe() + p.ZipWriter = zip.NewWriter(p.Pipewriter) + return p +} + +func (this *payloadWriter) getDataWriter() (io.Writer, error) { + return this.ZipWriter.Create("data") +} + +func (this *payloadWriter) getMetadataWriter() (io.Writer, error) { + return this.ZipWriter.Create("metadata") +} + +func (this *payloadWriter) Close() error { + if err := this.ZipWriter.Close(); err != nil { + return err + } + return this.Pipewriter.Close() + +} + +func (this *Payload) GetMode() string { + return string(this.BlockMode) +} + +func (this *Payload) GetHash() []byte { + return this.Hash +} + +func (this *Payload) GetKey() []byte { + return this.Key +} + +func (this *Payload) GetAlgorithm() string { + return string(this.Block) } func (this *Payload) GetHashMethod() string { - switch this.Hash { - case crypto.MD5: - return "md5" - case crypto.MD4: - return "md4" - case crypto.SHA1: - return "sha1" - case crypto.MD5SHA1: - return "md5sha1" - case crypto.RIPEMD160: - return "ripemd160" - case crypto.SHA224: - return "sha224" - case crypto.SHA256: - return "sha256" - case crypto.SHA384: - return "sha384" - case crypto.SHA512: - return "sha512" - default: - panic("unknown hash method") + return string(this.HashMethod) +} + +func (this *Payload) GetPayloadData() (io.Reader, error) { + pw := getPayloadWriter() + stream, err := this.getStreamAndCreateMetadata() + if err != nil { + return nil, err } + go func(payload *Payload, pw *payloadWriter) { + if mdw, err := pw.getMetadataWriter(); err != nil { + panic(err) + } else if err := payload.writeMetadata(mdw); err != nil { + panic(err) + } + + if mw, err := pw.getDataWriter(); err != nil { + panic(err) + } else if _, err := io.Copy(mw, payload.DataSource); err != nil { + panic(err) + } + if err := pw.Close(); err != nil { + panic(err) + } + }(this, pw) + + return this.encrypt(pw.Reader, stream) } -func (this *Payload) GetPayloadData() io.Reader { - // zip data source - - // create metadata - // zip the zipped data and metadata - - // encryptp everything togeter - return nil +func (this *Payload) writeMetadata(w io.Writer) error { + e := json.NewEncoder(w) + return e.Encode(this.getMetadata()) } -func (this *Payload) getStream() cipher.Stream { - return nil //this.BlockMode +func (this *Payload) getMetadata() *Metadata { + return &Metadata{IV: this.IV, Key: this.Key} } -func (this *Payload) encrypt(reader io.Reader) io.Reader { +func (this *Payload) getStreamAndCreateMetadata() (stream cipher.Stream, err error) { + var block cipher.Block + block, this.Key, err = this.Block.CreateBlock(this.Random) + if err != nil { + return + } + stream, this.IV, err = this.BlockMode.GetCipherStream(block, this.Random) + return +} + +func (this *Payload) computeHash(reader io.Reader) (io.Reader, error) { + readerHash := make(chan []byte) + read, err := this.HashMethod.HashOnTheWay(reader, readerHash) + if err != nil { + return nil, err + } + go func(readerHash chan []byte) { + this.Hash = <-readerHash + }(readerHash) + + return read, nil + +} + +func (this *Payload) encrypt(reader io.Reader, stream cipher.Stream) (io.Reader, error) { ret, writer := io.Pipe() - go func() { - cipherWriter := &cipher.StreamWriter{S: this.getStream(), W: writer} + go func(stream cipher.Stream) { + cipherWriter := &cipher.StreamWriter{S: stream, W: writer} io.Copy(cipherWriter, reader) cipherWriter.Close() - }() - return ret + }(stream) + return this.computeHash(ret) } diff --git a/payload/payload_test.go b/payload/payload_test.go index 885a907..6c2ee19 100644 --- a/payload/payload_test.go +++ b/payload/payload_test.go @@ -2,49 +2,144 @@ package payload import ( "bytes" - "crypto" + "errors" + "fmt" + "github.com/didiercrunch/ecrypto/helper" "io/ioutil" + "reflect" "testing" ) func TestPayloadGetHashMethod(t *testing.T) { p := new(Payload) - testCases := make(map[string]crypto.Hash) - testCases["md4"] = crypto.MD4 - testCases["md5"] = crypto.MD5 - testCases["sha1"] = crypto.SHA1 - testCases["sha224"] = crypto.SHA224 - testCases["sha256"] = crypto.SHA256 - testCases["sha384"] = crypto.SHA384 - testCases["sha512"] = crypto.SHA512 - testCases["md5sha1"] = crypto.MD5SHA1 - testCases["ripemd160"] = crypto.RIPEMD160 + testCases := make(map[string]Hash) + testCases["sha512"] = SHA512 for name, hashfunc := range testCases { - p.Hash = hashfunc + p.HashMethod = hashfunc if returnedName := p.GetHashMethod(); returnedName != name { t.Error("bad hash name. supposed to be ", name, " but received", returnedName) } } } -func TestGetStream(t *testing.T) { +func TestGetStreamAndCreateMetadata(t *testing.T) { p := new(Payload) - if s := p.getStream(); s != nil { + p.Block = AES256 + p.BlockMode = OFB + p.Random = helper.NewMockRandomReader() + if _, err := p.getStreamAndCreateMetadata(); err != nil { + t.Error(err) + } else if len(p.Key) != 256/8 { + t.Fail() + } else if len(p.IV) != 128/8 { t.Fail() } } func TestEncrypt(t *testing.T) { - if true { + p := new(Payload) + p.Block = AES256 + p.HashMethod = SHA512 + p.BlockMode = OFB + p.Random = helper.NewMockRandomReader() + data := bytes.NewBufferString("nice string") + stream, err := p.getStreamAndCreateMetadata() + if err != nil { + t.Error(err) return } - p := new(Payload) - data := bytes.NewBufferString("nice string") - reader := p.encrypt(data) - if outputdata, err := ioutil.ReadAll(reader); err != nil { + reader, err := p.encrypt(data, stream) + if err != nil { t.Error(err) - } else if string(outputdata) != "nice string" { - t.Fail() + return + } + go func(t *testing.T) { + if outputdata, err := ioutil.ReadAll(reader); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(outputdata, []byte{0, 124, 45, 17, 57, 48, 19, 154, 180, 15, 43}) { + t.Error("bad output data") + } + }(t) +} + +func TestGetMode(t *testing.T) { + p := new(Payload) + p.BlockMode = OFB + if p.GetMode() != "ofb" { + t.Error("bad block mode") + } +} + +func TestGetAlgorithm(t *testing.T) { + p := new(Payload) + p.Block = AES256 + if p.GetAlgorithm() != "aes256" { + t.Error("bad block") + } +} + +func TestPayloadWriter(t *testing.T) { + pw := getPayloadWriter() + go func(t *testing.T) { // Need this section! + if _, err := ioutil.ReadAll(pw.Reader); err != nil { + t.Error(err) + } + }(t) + if w, err := pw.getDataWriter(); err != nil { + t.Error(err) + } else { + fmt.Fprint(w, "some data") + } + + if w, err := pw.getMetadataWriter(); err != nil { + t.Error(err) + } else { + fmt.Fprint(w, "some meta data") + } + + if err := pw.Close(); err != nil { + t.Error(err) + } +} + +func TestWriteMetadata(t *testing.T) { + p := new(Payload) + p.Key = []byte{0, 1, 0, 1} + p.IV = []byte{10, 11, 10, 11} + w := helper.NewMockIoWriter() + if err := p.writeMetadata(w); err != nil { + t.Error(err) + return + } else if !w.IsValidJson() { + t.Error(w, "is not valid json") + } +} + +func TestGetPayloadData(t *testing.T) { + p := new(Payload) + p.DataSource = bytes.NewBufferString("some data to encrypt") + p.Block = AES256 + p.BlockMode = OFB + p.HashMethod = SHA512 + p.Random = helper.NewMockRandomReader() + r, err := p.GetPayloadData() + if err != nil { + t.Error(err) + return + } + errorC := make(chan error) + go func(errorC chan error) { + if _, err := ioutil.ReadAll(r); err != nil { + errorC <- err + } + errorC <- nil + }(errorC) + + if err := <-errorC; err != nil { + t.Error(err) + } else if len(p.GetHash()) != 512/8 { + fmt.Println(p.GetHash()) + errorC <- errors.New("hash has not been computed") } } diff --git a/something.go b/something.go deleted file mode 100644 index 95a12d9..0000000 --- a/something.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "io" -) - -type Params struct { -} - -type Envelop struct { - err error - params *Params -} - -func ZipIoReader(reader io.Reader) { - -} - -func createEnvelop(reader io.Reader, writer io.WriteCloser, params *Params) error { - env := &Envelop{nil, params} - env.ZipDataForPayload() - env.CreatePayloadMetadata() - env.EncryptPayload() - env.CreateEnvelopMetadata() - env.EncryptPayloadKeyAndAddItToEncelop() - return env.getError() -}