Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
98
pkg/security/encryptedstream.go
Normal file
98
pkg/security/encryptedstream.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type IEncryptedStream interface {
|
||||
Write(raw_data []byte) []byte
|
||||
Read(raw_data []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
const blockSize = 4096
|
||||
const headerSize = 16
|
||||
|
||||
type EncryptedStream struct {
|
||||
gcm_encrypter IEncryptor
|
||||
header []byte
|
||||
header_applied bool
|
||||
}
|
||||
type StreamOption func(EncryptedStream) (EncryptedStream, error)
|
||||
|
||||
func NewEncryptedStream(encryptor IEncryptor, options ...StreamOption) (IEncryptedStream, error) {
|
||||
var err error
|
||||
stream := EncryptedStream{gcm_encrypter: encryptor, header: nil, header_applied: false}
|
||||
for _, option := range options {
|
||||
stream, err = option(stream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &stream, nil
|
||||
}
|
||||
|
||||
func WithUniqueId(uniqueid []byte) StreamOption {
|
||||
return func(stream EncryptedStream) (EncryptedStream, error) {
|
||||
if len(uniqueid) == headerSize {
|
||||
stream.header = uniqueid
|
||||
stream.header_applied = false
|
||||
return stream, nil
|
||||
}
|
||||
return stream, errors.New("invalid file id - must be 16 bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *EncryptedStream) Write(rawData []byte) []byte {
|
||||
var length = len(rawData)
|
||||
highWatermark := 0
|
||||
byteStream := make([]byte, 0)
|
||||
index := 0
|
||||
if !s.header_applied {
|
||||
byteStream = append(byteStream, s.header...)
|
||||
s.header_applied = true
|
||||
}
|
||||
for index < length {
|
||||
highWatermark = int(math.Min(float64(length-index), float64(blockSize)))
|
||||
slice := s.gcm_encrypter.EncryptChunk(rawData[index:highWatermark])
|
||||
chunk_size := fmt.Sprintf("%04x", len(slice))
|
||||
byteStream = append(byteStream, chunk_size...)
|
||||
byteStream = append(byteStream, slice...)
|
||||
index += highWatermark
|
||||
}
|
||||
return byteStream
|
||||
}
|
||||
|
||||
func (s *EncryptedStream) Read(rawData []byte) ([]byte, error) {
|
||||
var length int64 = int64(len(rawData))
|
||||
byteStream := make([]byte, 0)
|
||||
if !s.header_applied && length < headerSize {
|
||||
return nil, errors.New("invalid stream")
|
||||
}
|
||||
var index int64 = 0
|
||||
|
||||
// read header
|
||||
if !s.header_applied {
|
||||
s.header = rawData[0:headerSize]
|
||||
s.header_applied = true
|
||||
index = headerSize
|
||||
}
|
||||
for index < length {
|
||||
nextBlockSize := "0x" + string(rawData[index:index+4])
|
||||
byte_slice_length, err := strconv.ParseInt(nextBlockSize, 0, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index += 4 // move index by 4 to actual data
|
||||
slice, err := s.gcm_encrypter.DecryptChunk(rawData[index:(index + byte_slice_length)])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byteStream = append(byteStream, slice...)
|
||||
index += byte_slice_length
|
||||
}
|
||||
return byteStream, nil
|
||||
}
|
||||
Reference in New Issue
Block a user