Skip to content

Commit

Permalink
add ces-kms
Browse files Browse the repository at this point in the history
  • Loading branch information
jojoliang committed May 14, 2021
1 parent 6097da8 commit 7134982
Show file tree
Hide file tree
Showing 12 changed files with 2,081 additions and 0 deletions.
67 changes: 67 additions & 0 deletions crypto/aes_ctr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package coscrypto

import (
"crypto/aes"
"crypto/cipher"
"io"
)

type aesCtr struct {
encrypter cipher.Stream
decrypter cipher.Stream
}

func newAesCtr(cd CipherData) (Cipher, error) {
block, err := aes.NewCipher(cd.Key)
if err != nil {
return nil, err
}
encrypter := cipher.NewCTR(block, cd.IV)
decrypter := cipher.NewCTR(block, cd.IV)
return &aesCtr{encrypter, decrypter}, nil
}

func (c *aesCtr) Encrypt(src io.Reader) io.Reader {
reader := &ctrEncryptReader{
encrypter: c.encrypter,
src: src,
}
return reader
}

type ctrEncryptReader struct {
encrypter cipher.Stream
src io.Reader
}

func (reader *ctrEncryptReader) Read(data []byte) (int, error) {
plainText := make([]byte, len(data), len(data))
n, err := reader.src.Read(plainText)
if n > 0 {
plainText = plainText[0:n]
reader.encrypter.XORKeyStream(data, plainText)
}
return n, err
}

func (c *aesCtr) Decrypt(src io.Reader) io.Reader {
return &ctrDecryptReader{
decrypter: c.decrypter,
src: src,
}
}

type ctrDecryptReader struct {
decrypter cipher.Stream
src io.Reader
}

func (reader *ctrDecryptReader) Read(data []byte) (int, error) {
cryptoText := make([]byte, len(data), len(data))
n, err := reader.src.Read(cryptoText)
if n > 0 {
cryptoText = cryptoText[0:n]
reader.decrypter.XORKeyStream(data, cryptoText)
}
return n, err
}
138 changes: 138 additions & 0 deletions crypto/aes_ctr_cipher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package coscrypto

import (
"io"
)

const (
aesKeySize = 32
ivSize = 16
)

type aesCtrCipherBuilder struct {
MasterCipher MasterCipher
}

type aesCtrCipher struct {
CipherData CipherData
Cipher Cipher
}

func CreateAesCtrBuilder(cipher MasterCipher) ContentCipherBuilder {
return aesCtrCipherBuilder{MasterCipher: cipher}
}

func (builder aesCtrCipherBuilder) createCipherData() (CipherData, error) {
var cd CipherData
var err error
err = cd.RandomKeyIv(aesKeySize, ivSize)
if err != nil {
return cd, err
}

cd.WrapAlgorithm = builder.MasterCipher.GetWrapAlgorithm()
cd.CEKAlgorithm = AesCtrAlgorithm
cd.MatDesc = builder.MasterCipher.GetMatDesc()

// EncryptedKey
cd.EncryptedKey, err = builder.MasterCipher.Encrypt(cd.Key)
if err != nil {
return cd, err
}

// EncryptedIV
cd.EncryptedIV, err = builder.MasterCipher.Encrypt(cd.IV)
if err != nil {
return cd, err
}

return cd, nil
}

func (builder aesCtrCipherBuilder) contentCipherCD(cd CipherData) (ContentCipher, error) {
cipher, err := newAesCtr(cd)
if err != nil {
return nil, err
}

return &aesCtrCipher{
CipherData: cd,
Cipher: cipher,
}, nil
}

func (builder aesCtrCipherBuilder) ContentCipher() (ContentCipher, error) {
cd, err := builder.createCipherData()
if err != nil {
return nil, err
}
return builder.contentCipherCD(cd)
}

func (builder aesCtrCipherBuilder) ContentCipherEnv(envelope Envelope) (ContentCipher, error) {
var cd CipherData
cd.EncryptedKey = make([]byte, len(envelope.CipherKey))
copy(cd.EncryptedKey, []byte(envelope.CipherKey))

plainKey, err := builder.MasterCipher.Decrypt([]byte(envelope.CipherKey))
if err != nil {
return nil, err
}
cd.Key = make([]byte, len(plainKey))
copy(cd.Key, plainKey)

cd.EncryptedIV = make([]byte, len(envelope.IV))
copy(cd.EncryptedIV, []byte(envelope.IV))

plainIV, err := builder.MasterCipher.Decrypt([]byte(envelope.IV))
if err != nil {
return nil, err
}

cd.IV = make([]byte, len(plainIV))
copy(cd.IV, plainIV)

cd.MatDesc = envelope.MatDesc
cd.WrapAlgorithm = envelope.WrapAlg
cd.CEKAlgorithm = envelope.CEKAlg

return builder.contentCipherCD(cd)
}

func (builder aesCtrCipherBuilder) GetMatDesc() string {
return builder.MasterCipher.GetMatDesc()
}

func (cc *aesCtrCipher) EncryptContent(src io.Reader) (io.ReadCloser, error) {
reader := cc.Cipher.Encrypt(src)
return &CryptoEncrypter{Body: src, Encrypter: reader}, nil
}

func (cc *aesCtrCipher) DecryptContent(src io.Reader) (io.ReadCloser, error) {
reader := cc.Cipher.Decrypt(src)
return &CryptoDecrypter{Body: src, Decrypter: reader}, nil
}

func (cc *aesCtrCipher) GetCipherData() *CipherData {
return &(cc.CipherData)
}

func (cc *aesCtrCipher) GetEncryptedLen(plainTextLen int64) int64 {
return plainTextLen
}

func (cc *aesCtrCipher) GetAlignLen() int {
return len(cc.CipherData.IV)
}

func (cc *aesCtrCipher) Clone(cd CipherData) (ContentCipher, error) {
cipher, err := newAesCtr(cd)
if err != nil {
return nil, err
}

return &aesCtrCipher{
CipherData: cd,
Cipher: cipher,
}, nil
}
107 changes: 107 additions & 0 deletions crypto/aes_ctr_cipher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package coscrypto_test

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"github.com/stretchr/testify/assert"
"github.com/tencentyun/cos-go-sdk-v5/crypto"
"io/ioutil"
math_rand "math/rand"
)

type EmptyMasterCipher struct{}

func (mc EmptyMasterCipher) Encrypt(b []byte) ([]byte, error) {
return b, nil
}
func (mc EmptyMasterCipher) Decrypt(b []byte) ([]byte, error) {
return b, nil
}
func (mc EmptyMasterCipher) GetWrapAlgorithm() string {
return "Test/EmptyWrapAlgo"
}
func (mc EmptyMasterCipher) GetMatDesc() string {
return "Empty Desc"
}

func (s *CosTestSuite) TestCryptoObjectService_EncryptAndDecrypt() {
var masterCipher EmptyMasterCipher
builder := coscrypto.CreateAesCtrBuilder(masterCipher)

contentCipher, err := builder.ContentCipher()
assert.Nil(s.T(), err, "CryptoObject.CreateAesCtrBuilder Failed")

dataSize := math_rand.Int63n(1024 * 1024 * 32)
originData := make([]byte, dataSize)
rand.Read(originData)
// 加密
r1 := bytes.NewReader(originData)
reader1, err := contentCipher.EncryptContent(r1)
assert.Nil(s.T(), err, "CryptoObject.contentCipher.Encrypt Failed")
encryptedData, err := ioutil.ReadAll(reader1)
assert.Nil(s.T(), err, "CryptoObject.Read Failed")

// 解密
r2 := bytes.NewReader(encryptedData)
reader2, err := contentCipher.DecryptContent(r2)
decryptedData, err := ioutil.ReadAll(reader2)
assert.Nil(s.T(), err, "CryptoObject.Read Failed")
assert.Equal(s.T(), bytes.Compare(originData, decryptedData), 0, "decryptData != originData")
}

func (s *CosTestSuite) TestCryptoObjectService_Encrypt() {
var masterCipher EmptyMasterCipher
builder := coscrypto.CreateAesCtrBuilder(masterCipher)

contentCipher, err := builder.ContentCipher()
assert.Nil(s.T(), err, "CryptoObject.CreateAesCtrBuilder Failed")

dataSize := math_rand.Int63n(1024 * 1024 * 32)
originData := make([]byte, dataSize)
rand.Read(originData)

// 加密
r := bytes.NewReader(originData)
reader, err := contentCipher.EncryptContent(r)
assert.Nil(s.T(), err, "CryptoObject.contentCipher.Encrypt Failed")
encryptedData, err := ioutil.ReadAll(reader)
assert.Nil(s.T(), err, "CryptoObject.Read Failed")

// 直接解密
cd := contentCipher.GetCipherData()
block, err := aes.NewCipher(cd.Key)
assert.Nil(s.T(), err, "CryptoObject.NewCipher Failed")
decrypter := cipher.NewCTR(block, cd.IV)
decryptedData := make([]byte, len(originData))
decrypter.XORKeyStream(decryptedData, encryptedData)
assert.Equal(s.T(), bytes.Compare(originData, decryptedData), 0, "decryptData != originData")
}

func (s *CosTestSuite) TestCryptoObjectService_Decrypt() {
var masterCipher EmptyMasterCipher
builder := coscrypto.CreateAesCtrBuilder(masterCipher)

contentCipher, err := builder.ContentCipher()
assert.Nil(s.T(), err, "CryptoObject.CreateAesCtrBuilder Failed")
dataSize := math_rand.Int63n(1024 * 1024 * 32)
originData := make([]byte, dataSize)
rand.Read(originData)

// 直接加密
cd := contentCipher.GetCipherData()
block, err := aes.NewCipher(cd.Key)
assert.Nil(s.T(), err, "CryptoObject.NewCipher Failed")
encrypter := cipher.NewCTR(block, cd.IV)
encryptedData := make([]byte, len(originData))
encrypter.XORKeyStream(encryptedData, originData)

// 解密
r := bytes.NewReader(encryptedData)
reader, err := contentCipher.DecryptContent(r)
assert.Nil(s.T(), err, "CryptoObject.contentCipher.Encrypt Failed")
decryptedData, err := ioutil.ReadAll(reader)
assert.Nil(s.T(), err, "CryptoObject.Read Failed")
assert.Equal(s.T(), bytes.Compare(originData, decryptedData), 0, "decryptData != originData")
}
69 changes: 69 additions & 0 deletions crypto/cipher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package coscrypto

import (
"io"
)

// Cipher is interface for encryption or decryption of an object
type Cipher interface {
Encrypter
Decrypter
}

// Encrypter is interface with only encrypt method
type Encrypter interface {
Encrypt(io.Reader) io.Reader
}

// Decrypter is interface with only decrypt method
type Decrypter interface {
Decrypt(io.Reader) io.Reader
}

// CryptoEncrypter provides close method for Encrypter
type CryptoEncrypter struct {
Body io.Reader
Encrypter io.Reader
isClosed bool
}

// Close lets the CryptoEncrypter satisfy io.ReadCloser interface
func (rc *CryptoEncrypter) Close() error {
rc.isClosed = true
if closer, ok := rc.Body.(io.ReadCloser); ok {
return closer.Close()
}
return nil
}

// Read lets the CryptoEncrypter satisfy io.ReadCloser interface
func (rc *CryptoEncrypter) Read(b []byte) (int, error) {
if rc.isClosed {
return 0, io.EOF
}
return rc.Encrypter.Read(b)
}

// CryptoDecrypter provides close method for Decrypter
type CryptoDecrypter struct {
Body io.Reader
Decrypter io.Reader
isClosed bool
}

// Close lets the CryptoDecrypter satisfy io.ReadCloser interface
func (rc *CryptoDecrypter) Close() error {
rc.isClosed = true
if closer, ok := rc.Body.(io.ReadCloser); ok {
return closer.Close()
}
return nil
}

// Read lets the CryptoDecrypter satisfy io.ReadCloser interface
func (rc *CryptoDecrypter) Read(b []byte) (int, error) {
if rc.isClosed {
return 0, io.EOF
}
return rc.Decrypter.Read(b)
}

0 comments on commit 7134982

Please sign in to comment.