--- /dev/null
+package osscrypto
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "io"
+ math_rand "math/rand"
+ "time"
+)
+
+// MasterCipher encrypt or decrpt CipherData
+// support master key: rsa && ali kms
+type MasterCipher interface {
+ Encrypt([]byte) ([]byte, error)
+ Decrypt([]byte) ([]byte, error)
+ GetWrapAlgorithm() string
+ GetMatDesc() string
+}
+
+// ContentCipherBuilder is used to create ContentCipher for encryting object's data
+type ContentCipherBuilder interface {
+ ContentCipher() (ContentCipher, error)
+ ContentCipherEnv(Envelope) (ContentCipher, error)
+ GetMatDesc() string
+}
+
+// ContentCipher is used to encrypt or decrypt object's data
+type ContentCipher interface {
+ EncryptContent(io.Reader) (io.ReadCloser, error)
+ DecryptContent(io.Reader) (io.ReadCloser, error)
+ Clone(cd CipherData) (ContentCipher, error)
+ GetEncryptedLen(int64) int64
+ GetCipherData() *CipherData
+ GetAlignLen() int
+}
+
+// Envelope is stored in oss object's meta
+type Envelope struct {
+ IV string
+ CipherKey string
+ MatDesc string
+ WrapAlg string
+ CEKAlg string
+ UnencryptedMD5 string
+ UnencryptedContentLen string
+}
+
+func (el Envelope) IsValid() bool {
+ return len(el.IV) > 0 &&
+ len(el.CipherKey) > 0 &&
+ len(el.WrapAlg) > 0 &&
+ len(el.CEKAlg) > 0
+}
+
+func (el Envelope) String() string {
+ return fmt.Sprintf("IV=%s&CipherKey=%s&WrapAlg=%s&CEKAlg=%s", el.IV, el.CipherKey, el.WrapAlg, el.CEKAlg)
+}
+
+// CipherData is secret key information
+type CipherData struct {
+ IV []byte
+ Key []byte
+ MatDesc string
+ WrapAlgorithm string
+ CEKAlgorithm string
+ EncryptedIV []byte
+ EncryptedKey []byte
+}
+
+func (cd *CipherData) RandomKeyIv(keyLen int, ivLen int) error {
+ math_rand.Seed(time.Now().UnixNano())
+
+ // Key
+ cd.Key = make([]byte, keyLen)
+ if _, err := io.ReadFull(rand.Reader, cd.Key); err != nil {
+ return err
+ }
+
+ // sizeof uint64
+ if ivLen < 8 {
+ return fmt.Errorf("ivLen:%d less than 8", ivLen)
+ }
+
+ // IV:reserve 8 bytes
+ cd.IV = make([]byte, ivLen)
+ if _, err := io.ReadFull(rand.Reader, cd.IV[0:ivLen-8]); err != nil {
+ return err
+ }
+
+ // only use 4 byte,in order not to overflow when SeekIV()
+ randNumber := math_rand.Uint32()
+ cd.SetIV(uint64(randNumber))
+ return nil
+}
+
+func (cd *CipherData) SetIV(iv uint64) {
+ ivLen := len(cd.IV)
+ binary.BigEndian.PutUint64(cd.IV[ivLen-8:], iv)
+}
+
+func (cd *CipherData) GetIV() uint64 {
+ ivLen := len(cd.IV)
+ return binary.BigEndian.Uint64(cd.IV[ivLen-8:])
+}
+
+func (cd *CipherData) SeekIV(startPos uint64) {
+ cd.SetIV(cd.GetIV() + startPos/uint64(len(cd.IV)))
+}
+
+func (cd *CipherData) Clone() CipherData {
+ var cloneCd CipherData
+ cloneCd = *cd
+
+ cloneCd.Key = make([]byte, len(cd.Key))
+ copy(cloneCd.Key, cd.Key)
+
+ cloneCd.IV = make([]byte, len(cd.IV))
+ copy(cloneCd.IV, cd.IV)
+
+ cloneCd.EncryptedIV = make([]byte, len(cd.EncryptedIV))
+ copy(cloneCd.EncryptedIV, cd.EncryptedIV)
+
+ cloneCd.EncryptedKey = make([]byte, len(cd.EncryptedKey))
+ copy(cloneCd.EncryptedKey, cd.EncryptedKey)
+
+ return cloneCd
+}