-
[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모드의 보안 취약점때문에 메소드를 지원하지 않습니다. 따라서 위와 같이 직접 구현해야 합니다.