|
|
package coscrypto
import ( "crypto/rand" "encoding/binary" "fmt" "io" math_rand "math/rand" "time" )
const ( COSClientSideEncryptionKey string = "x-cos-meta-client-side-encryption-key" COSClientSideEncryptionStart = "x-cos-meta-client-side-encryption-start" COSClientSideEncryptionCekAlg = "x-cos-meta-client-side-encryption-cek-alg" COSClientSideEncryptionWrapAlg = "x-cos-meta-client-side-encryption-wrap-alg" COSClientSideEncryptionMatDesc = "x-cos-meta-client-side-encryption-matdesc" COSClientSideEncryptionUnencryptedContentLength = "x-cos-meta-client-side-encryption-unencrypted-content-length" COSClientSideEncryptionUnencryptedContentMD5 = "x-cos-meta-client-side-encryption-unencrypted-content-md5" COSClientSideEncryptionDataSize = "x-cos-meta-client-side-encryption-data-size" COSClientSideEncryptionPartSize = "x-cos-meta-client-side-encryption-part-size" UserAgent = "User-Agent" )
const ( CosKmsCryptoWrap = "KMS/TencentCloud" AesCtrAlgorithm = "AES/CTR/NoPadding" EncryptionUaSuffix = "COSEncryptionClient" )
type MasterCipher interface { Encrypt([]byte) ([]byte, error) Decrypt([]byte) ([]byte, error) GetWrapAlgorithm() string GetMatDesc() string }
type ContentCipherBuilder interface { ContentCipher() (ContentCipher, error) ContentCipherEnv(Envelope) (ContentCipher, error) GetMatDesc() string }
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 }
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) }
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: | nonce: 8 bytes | Serial number: 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 }
|