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) }