339 lines
11 KiB
Go
339 lines
11 KiB
Go
package symm
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/rand"
|
|
"errors"
|
|
"io"
|
|
|
|
"b612.me/starcrypto/paddingx"
|
|
)
|
|
|
|
const (
|
|
PKCS5PADDING = paddingx.PKCS5
|
|
PKCS7PADDING = paddingx.PKCS7
|
|
ZEROPADDING = paddingx.ZERO
|
|
ANSIX923PADDING = paddingx.ANSIX923
|
|
)
|
|
|
|
var (
|
|
ErrInvalidGCMNonceLength = errors.New("gcm nonce length must be 12 bytes")
|
|
ErrInvalidCCMNonceLength = errors.New("ccm nonce length must be 12 bytes")
|
|
)
|
|
|
|
const (
|
|
aeadCCMTagSize = 16
|
|
aeadCCMNonceSize = 12
|
|
)
|
|
|
|
var (
|
|
aesGCMFactory = newGCMFactory(aes.NewCipher)
|
|
aesCCMFactory = newCCMFactory(aes.NewCipher)
|
|
)
|
|
|
|
func EncryptAes(data, key, iv []byte, mode, paddingType string) ([]byte, error) {
|
|
return encryptBlockCipher(data, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, EncryptAesGCM, EncryptAesCCM)
|
|
}
|
|
|
|
func DecryptAes(src, key, iv []byte, mode, paddingType string) ([]byte, error) {
|
|
return decryptBlockCipher(src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, DecryptAesGCM, DecryptAesCCM)
|
|
}
|
|
|
|
func EncryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
|
|
return encryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, EncryptAesGCMStream, EncryptAesCCMStream)
|
|
}
|
|
|
|
func DecryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
|
|
return decryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, DecryptAesGCMStream, DecryptAesCCMStream)
|
|
}
|
|
|
|
func EncryptAesWithOptions(data, key []byte, opts *CipherOptions) ([]byte, error) {
|
|
return encryptBlockWithOptions(data, key, opts, EncryptAesGCM, EncryptAesCCM, EncryptAes)
|
|
}
|
|
|
|
func DecryptAesWithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) {
|
|
return decryptBlockWithOptions(src, key, opts, DecryptAesGCM, DecryptAesCCM, DecryptAes)
|
|
}
|
|
|
|
func EncryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
|
|
return encryptBlockStreamWithOptions(dst, src, key, opts, EncryptAesGCMStream, EncryptAesCCMStream, EncryptAesStream)
|
|
}
|
|
|
|
func DecryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
|
|
return decryptBlockStreamWithOptions(dst, src, key, opts, DecryptAesGCMStream, DecryptAesCCMStream, DecryptAesStream)
|
|
}
|
|
|
|
func EncryptAesGCM(plain, key, nonce, aad []byte) ([]byte, error) {
|
|
return encryptAEAD(aesGCMFactory, plain, key, nonce, aad, ErrInvalidGCMNonceLength)
|
|
}
|
|
|
|
func DecryptAesGCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
|
|
return decryptAEAD(aesGCMFactory, ciphertext, key, nonce, aad, ErrInvalidGCMNonceLength)
|
|
}
|
|
|
|
func EncryptAesCCM(plain, key, nonce, aad []byte) ([]byte, error) {
|
|
return encryptAEAD(aesCCMFactory, plain, key, nonce, aad, ErrInvalidCCMNonceLength)
|
|
}
|
|
|
|
func DecryptAesCCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
|
|
return decryptAEAD(aesCCMFactory, ciphertext, key, nonce, aad, ErrInvalidCCMNonceLength)
|
|
}
|
|
|
|
func EncryptAesCCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
|
|
return encryptAEADChunk(aesCCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, encryptCCMChunk)
|
|
}
|
|
|
|
func DecryptAesCCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
|
|
return decryptAEADChunk(aesCCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, decryptCCMChunk)
|
|
}
|
|
|
|
func EncryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
|
return encryptAEADStream(aesCCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, encryptCCMChunkedStream)
|
|
}
|
|
|
|
func DecryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
|
return decryptAEADStream(aesCCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, decryptCCMChunkedOrLegacyStream)
|
|
}
|
|
|
|
func EncryptAesGCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
|
|
return encryptAEADChunk(aesGCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, encryptGCMChunk)
|
|
}
|
|
|
|
func DecryptAesGCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
|
|
return decryptAEADChunk(aesGCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, decryptGCMChunk)
|
|
}
|
|
|
|
func EncryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
|
return encryptAEADStream(aesGCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, encryptGCMChunkedStream)
|
|
}
|
|
|
|
func DecryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
|
return decryptAEADStream(aesGCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, decryptGCMChunkedOrLegacyStream)
|
|
}
|
|
func EncryptAesECB(data, key []byte, paddingType string) ([]byte, error) {
|
|
return EncryptAes(data, key, nil, MODEECB, paddingType)
|
|
}
|
|
|
|
func DecryptAesECB(src, key []byte, paddingType string) ([]byte, error) {
|
|
return DecryptAes(src, key, nil, MODEECB, paddingType)
|
|
}
|
|
|
|
func EncryptAesCBC(data, key, iv []byte, paddingType string) ([]byte, error) {
|
|
return EncryptAes(data, key, iv, MODECBC, paddingType)
|
|
}
|
|
|
|
func DecryptAesCBC(src, key, iv []byte, paddingType string) ([]byte, error) {
|
|
return DecryptAes(src, key, iv, MODECBC, paddingType)
|
|
}
|
|
|
|
func EncryptAesCFB(data, key, iv []byte) ([]byte, error) {
|
|
return EncryptAes(data, key, iv, MODECFB, "")
|
|
}
|
|
|
|
func DecryptAesCFB(src, key, iv []byte) ([]byte, error) {
|
|
return DecryptAes(src, key, iv, MODECFB, "")
|
|
}
|
|
|
|
func EncryptAesOFB(data, key, iv []byte) ([]byte, error) {
|
|
return EncryptAes(data, key, iv, MODEOFB, "")
|
|
}
|
|
|
|
func DecryptAesOFB(src, key, iv []byte) ([]byte, error) {
|
|
return DecryptAes(src, key, iv, MODEOFB, "")
|
|
}
|
|
|
|
func EncryptAesCTR(data, key, iv []byte) ([]byte, error) {
|
|
return EncryptAes(data, key, iv, MODECTR, "")
|
|
}
|
|
|
|
func DecryptAesCTR(src, key, iv []byte) ([]byte, error) {
|
|
return DecryptAes(src, key, iv, MODECTR, "")
|
|
}
|
|
|
|
func EncryptAesCTRAt(data, key, iv []byte, offset int64) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return xorCTRAtOffset(block, data, iv, offset)
|
|
}
|
|
|
|
func DecryptAesCTRAt(src, key, iv []byte, offset int64) ([]byte, error) {
|
|
return EncryptAesCTRAt(src, key, iv, offset)
|
|
}
|
|
|
|
func EncryptAesECBStream(dst io.Writer, src io.Reader, key []byte, paddingType string) error {
|
|
return EncryptAesStream(dst, src, key, nil, MODEECB, paddingType)
|
|
}
|
|
|
|
func DecryptAesECBStream(dst io.Writer, src io.Reader, key []byte, paddingType string) error {
|
|
return DecryptAesStream(dst, src, key, nil, MODEECB, paddingType)
|
|
}
|
|
|
|
func EncryptAesCBCStream(dst io.Writer, src io.Reader, key, iv []byte, paddingType string) error {
|
|
return EncryptAesStream(dst, src, key, iv, MODECBC, paddingType)
|
|
}
|
|
|
|
func DecryptAesCBCStream(dst io.Writer, src io.Reader, key, iv []byte, paddingType string) error {
|
|
return DecryptAesStream(dst, src, key, iv, MODECBC, paddingType)
|
|
}
|
|
|
|
func EncryptAesCFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return EncryptAesStream(dst, src, key, iv, MODECFB, "")
|
|
}
|
|
|
|
func DecryptAesCFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return DecryptAesStream(dst, src, key, iv, MODECFB, "")
|
|
}
|
|
|
|
func EncryptAesOFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return EncryptAesStream(dst, src, key, iv, MODEOFB, "")
|
|
}
|
|
|
|
func DecryptAesOFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return DecryptAesStream(dst, src, key, iv, MODEOFB, "")
|
|
}
|
|
|
|
func EncryptAesCTRStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return EncryptAesStream(dst, src, key, iv, MODECTR, "")
|
|
}
|
|
|
|
func DecryptAesCTRStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
return DecryptAesStream(dst, src, key, iv, MODECTR, "")
|
|
}
|
|
|
|
func CustomEncryptAesCFB(origData, key []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
encrypted := make([]byte, aes.BlockSize+len(origData))
|
|
iv := encrypted[:block.BlockSize()]
|
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
body, err := EncryptAesCFB(origData, key, iv)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy(encrypted[block.BlockSize():], body)
|
|
return encrypted, nil
|
|
}
|
|
|
|
func CustomDecryptAesCFB(encrypted, key []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(encrypted) < block.BlockSize() {
|
|
return nil, errors.New("ciphertext too short")
|
|
}
|
|
|
|
iv := encrypted[:block.BlockSize()]
|
|
return DecryptAesCFB(encrypted[block.BlockSize():], key, iv)
|
|
}
|
|
|
|
func CustomEncryptAesCFBNoBlock(origData, key, iv []byte) ([]byte, error) {
|
|
return EncryptAesCFB(origData, key, iv)
|
|
}
|
|
|
|
func CustomDecryptAesCFBNoBlock(encrypted, key, iv []byte) ([]byte, error) {
|
|
return DecryptAesCFB(encrypted, key, iv)
|
|
}
|
|
|
|
func PKCS5Padding(cipherText []byte, blockSize int) []byte {
|
|
out, _ := paddingx.Pad(cipherText, blockSize, PKCS5PADDING)
|
|
return out
|
|
}
|
|
|
|
func PKCS5Trimming(encrypted []byte) []byte {
|
|
if len(encrypted) == 0 {
|
|
return nil
|
|
}
|
|
padding := int(encrypted[len(encrypted)-1])
|
|
if padding <= 0 || padding > len(encrypted) {
|
|
return nil
|
|
}
|
|
for i := len(encrypted) - padding; i < len(encrypted); i++ {
|
|
if int(encrypted[i]) != padding {
|
|
return nil
|
|
}
|
|
}
|
|
return encrypted[:len(encrypted)-padding]
|
|
}
|
|
|
|
func PKCS7Padding(cipherText []byte, blockSize int) []byte {
|
|
out, _ := paddingx.Pad(cipherText, blockSize, PKCS7PADDING)
|
|
return out
|
|
}
|
|
|
|
func PKCS7Trimming(encrypted []byte, blockSize int) []byte {
|
|
out, err := paddingx.Unpad(encrypted, blockSize, PKCS7PADDING)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return out
|
|
}
|
|
|
|
func EncryptAesCFB8(data, key, iv []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return encryptCFB8(block, data, iv)
|
|
}
|
|
|
|
func DecryptAesCFB8(src, key, iv []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return decryptCFB8(block, src, iv)
|
|
}
|
|
|
|
func EncryptAesCFB8Stream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return encryptCFB8Stream(block, dst, src, iv, false)
|
|
}
|
|
|
|
func DecryptAesCFB8Stream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return encryptCFB8Stream(block, dst, src, iv, true)
|
|
}
|
|
|
|
func DecryptAesECBBlocks(src, key []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return decryptECBBlocks(block, src)
|
|
}
|
|
|
|
// DecryptAesCBCFromSecondBlock decrypts a CBC ciphertext segment that starts from block 2 or later.
|
|
// prevCipherBlock must be the previous ciphertext block. For data from block 2, pass block 1 as prevCipherBlock.
|
|
func DecryptAesCBCFromSecondBlock(src, key, prevCipherBlock []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return decryptCBCFromSecondBlock(block, src, prevCipherBlock)
|
|
}
|
|
|
|
// DecryptAesCFBFromSecondBlock decrypts a CFB ciphertext segment that starts from block 2 or later.
|
|
// prevCipherBlock must be the previous ciphertext block. For data from block 2, pass block 1 as prevCipherBlock.
|
|
func DecryptAesCFBFromSecondBlock(src, key, prevCipherBlock []byte) ([]byte, error) {
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return decryptCFBFromSecondBlock(block, src, prevCipherBlock)
|
|
}
|