-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
jojoliang
committed
May 14, 2021
1 parent
6097da8
commit 7134982
Showing
12 changed files
with
2,081 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
Oops, something went wrong.