ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Golang] AES ECB 모드 암호화 (PKCS5, PKCS7)
    언어/Golang 2017. 2. 17. 15:24


    package main
    import (
    	"bytes"
    	"crypto/aes"
    	"crypto/cipher"
    	"encoding/base64"
    	"fmt"
    	"strings"
    )
    func main() {
    	/*
    	 *src 암호화 대상
    	 *key 암호 key, 16bit면 AES-128, 32bit면 AES-256
    	 */
    	src := "테스트 평문"
    	key := "0123456789abcdef"
    	crypted := AesEncrypt(src, key)
    	AesDecrypt(crypted, []byte(key))
    	Base64URLDecode("")
    }
    func Base64URLDecode(data string) ([]byte, error) {
    	var missing = (4 - len(data)%4) % 4
    	data += strings.Repeat("=", missing)
    	res, err := base64.URLEncoding.DecodeString(data)
    	fmt.Println("  decodebase64urlsafe is :", string(res), err)
    	return base64.URLEncoding.DecodeString(data)
    }
    func Base64UrlSafeEncode(source []byte) string {
    	// Base64 Url Safe is the same as Base64 but does not contain '/' and '+' (replaced by '_' and '-') and trailing '=' are removed.
    	bytearr := base64.StdEncoding.EncodeToString(source)
    	safeurl := strings.Replace(string(bytearr), "/", "_", -1)
    	safeurl = strings.Replace(safeurl, "+", "-", -1)
    	safeurl = strings.Replace(safeurl, "=", "", -1)
    	return safeurl
    }
    func AesDecrypt(crypted, key []byte) []byte {
    	block, err := aes.NewCipher(key)
    	if err != nil {
    		fmt.Println("err is:", err)
    	}
    	blockMode := NewECBDecrypter(block)
    	origData := make([]byte, len(crypted))
    	blockMode.CryptBlocks(origData, crypted)
    	origData = PKCS5UnPadding(origData)
    	fmt.Println("source is :", origData, string(origData))
    	return origData
    }
    func AesEncrypt(src, key string) []byte {
    	block, err := aes.NewCipher([]byte(key))
    	if err != nil {
    		fmt.Println("key error1", err)
    	}
    	if src == "" {
    		fmt.Println("plain content empty")
    	}
    	ecb := NewECBEncrypter(block)
    	content := []byte(src)
    	content = PKCS5Padding(content, block.BlockSize())
    	crypted := make([]byte, len(content))
    	ecb.CryptBlocks(crypted, content)
    	fmt.Println("base64 result:", base64.StdEncoding.EncodeToString(crypted))
    	fmt.Println("base64UrlSafe result:", Base64UrlSafeEncode(crypted))
    	return crypted
    }
    /*
    PKCS 방식에 따라 아래 함수들은 암, 복호화 함수 내에서 변경
    */
    func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    	padding := blockSize - len(ciphertext)%blockSize
    	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    	return append(ciphertext, padtext...)
    }
    func PKCS5UnPadding(origData []byte) []byte {
    	length := len(origData)
    	// 去掉最后一个字节 unpadding 次
    	unpadding := int(origData[length-1])
    	return origData[:(length - unpadding)]
    }
    func pkcs7Pad(data []byte, blocklen int) ([]byte, error) {
    	if blocklen <= 0 {
    		return nil, fmt.Errorf("invalid blocklen %d", blocklen)
    	}
    	padlen := 1
    	for ((len(data) + padlen) % blocklen) != 0 {
    		padlen = padlen + 1
    	}
    	pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
    	return append(data, pad...), nil
    }
    func pkcs7Unpad(data []byte) ([]byte, error) {
    	padlen := int(data[len(data)-1])
    	// check padding
    	pad := data[len(data)-padlen:]
    	for i := 0; i < padlen; i++ {
    		if pad[i] != byte(padlen) {
    			return nil, fmt.Errorf("invalid padding")
    		}
    	}
    	return data[:len(data)-padlen], nil
    }
    type ecb struct {
    	b         cipher.Block
    	blockSize int
    }
    func newECB(b cipher.Block) *ecb {
    	return &ecb{
    		b:         b,
    		blockSize: b.BlockSize(),
    	}
    }
    type ecbEncrypter ecb
    // NewECBEncrypter returns a BlockMode which encrypts in electronic code book
    // mode, using the given Block.
    func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
    	return (*ecbEncrypter)(newECB(b))
    }
    func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
    func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
    	if len(src)%x.blockSize != 0 {
    		panic("crypto/cipher: input not full blocks")
    	}
    	if len(dst) < len(src) {
    		panic("crypto/cipher: output smaller than input")
    	}
    	for len(src) > 0 {
    		x.b.Encrypt(dst, src[:x.blockSize])
    		src = src[x.blockSize:]
    		dst = dst[x.blockSize:]
    	}
    }
    type ecbDecrypter ecb
    // NewECBDecrypter returns a BlockMode which decrypts in electronic code book
    // mode, using the given Block.
    func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
    	return (*ecbDecrypter)(newECB(b))
    }
    func (x *ecbDecrypter) BlockSize() int { return x.blockSize }
    func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
    	if len(src)%x.blockSize != 0 {
    		panic("crypto/cipher: input not full blocks")
    	}
    	if len(dst) < len(src) {
    		panic("crypto/cipher: output smaller than input")
    	}
    	for len(src) > 0 {
    		x.b.Decrypt(dst, src[:x.blockSize])
    		src = src[x.blockSize:]
    		dst = dst[x.blockSize:]
    	}
    }
    


    Go에서는 AES의 ECB모드의 보안 취약점때문에 메소드를 지원하지 않습니다. 따라서 위와 같이 직접 구현해야 합니다.

    댓글