// Author : Eric Kim // Build Date : 23 Jul 2018 Last Update 02 Aug 2018 // End-Agent for Passcon Multi OS go binding with Windows, MacOS, iOS, and Android // All rights are reserved. package etc import ( "bytes" "crypto" "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "io" "math/big" "strings" ) func RsaPrPbPair(keyLeng int) ([]byte, []byte) { prKey, _ := rsa.GenerateKey(rand.Reader, keyLeng) pbKey := &prKey.PublicKey prBytes := x509.MarshalPKCS1PrivateKey(prKey) prMem := pem.EncodeToMemory(&pem.Block{ Type: "RSA PRIVATE KEY", Bytes: prBytes, }) // Bytes: 에 직접 넣으면 런타임에서 에러남.(중요!!) pbBytes, err := x509.MarshalPKIXPublicKey(pbKey) if err != nil { fmt.Println(err) } pbMem := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: pbBytes, }) return prMem, pbMem } func RsaSignature(prKey []byte, msg []byte) ([]byte, error) { // msg 245=(256-11)bytes 이하 block, _ := pem.Decode(prKey) if block == nil { return nil, MyErr("QROPBDHCF-pem.Decode", nil, false) } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, MyErr("QERDVAEQYG-x509.ParsePKCS1PrivateKey", err, false) } sign, err := rsa.SignPKCS1v15(nil, priv, crypto.Hash(0), msg) if err != nil { return nil, MyErr("CZGSRFVA-rsa.SignPKCS1v15", err, false) } return sign, nil } func RsaOriginal(pubKey []byte, msg []byte) ([]byte, error) { block, _ := pem.Decode(pubKey) if block == nil { return nil, MyErr("ADYERFBJ-pem.Decode", nil, false) } pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, MyErr("MNCHSTRGB-x509.ParsePKIXPublicKey", err, false) } pbKey := pubInterface.(*rsa.PublicKey) c := new(big.Int) m := new(big.Int) m.SetBytes(msg) e := big.NewInt(int64(pbKey.E)) c.Exp(m, e, pbKey.N) out := c.Bytes() skip := 0 for i := 2; i < len(out); i++ { if i+1 >= len(out) { break } if out[i] == 0xff && out[i+1] == 0 { skip = i + 2 break } } return out[skip:], nil } func RsaPbEncrypt(publicKey []byte, msg []byte) ([]byte, error) { origData := msg block, _ := pem.Decode(publicKey) if block == nil { return nil, MyErr("QEROBVSRAE-pem.Decode", nil, false) } pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, MyErr("KDGBSAERT-x509.ParsePKIXPublicKey", err, false) } pub := pubInterface.(*rsa.PublicKey) label := []byte("") sha256hash := sha256.New() enBytes, err := rsa.EncryptOAEP(sha256hash, rand.Reader, pub, origData, label) if err != nil { return nil, MyErr("rsa.EncryptOAEP", err, false) } return enBytes, nil } func RsaPrDecrypt(privateKey []byte, msg []byte) ([]byte, error) { ciphertext := msg block, _ := pem.Decode(privateKey) if block == nil { return nil, MyErr("USFBSHWER-pem.Decode", nil, false) } priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, MyErr("MTVZQFGAEW-x509.ParsePKCS1PrivateKey", err, false) } label := []byte("") sha256hash := sha256.New() deBytes, err := rsa.DecryptOAEP(sha256hash, rand.Reader, priv, ciphertext, label) if err != nil { return nil, MyErr("QGOTRVBAE-rsa.DecryptOAEP", err, false) } return deBytes, nil } func AddBase64Padding(value string) string { m := len(value) % 4 if m != 0 { value += strings.Repeat("=", 4-m) } return value } func RemoveBase64Padding(value string) string { return strings.Replace(value, "=", "", -1) } func AesPad(src []byte) []byte { padding := aes.BlockSize - len(src)%aes.BlockSize padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(src, padtext...) } func AesUnpad(src []byte) ([]byte, error) { length := len(src) unpadding := int(src[length-1]) if unpadding > length { return nil, errors.New("OYNSTBZE-unpad error. This could happen when incorrect myEncryption key is used") } return src[:(length - unpadding)], nil } func AesEncrypt(key []byte, text []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { fmt.Println("WERFAV-Error: NewCipher in myEncrypt - " + err.Error()) return nil, err } msg := AesPad(text) ciphertext := make([]byte, aes.BlockSize+len(msg)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return nil, MyErr("-NYTZVCEF-io.ReadFull", err, false) } cfb := cipher.NewCFBEncrypter(block, iv) cfb.XORKeyStream(ciphertext[aes.BlockSize:], msg) finalMsg := RemoveBase64Padding(base64.URLEncoding.EncodeToString(ciphertext)) return []byte(finalMsg), nil } func AesDecrypt(key []byte, text []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, MyErr("YGBARZDF-aes.NewCipher", err, false) } decodedMsg, err := base64.URLEncoding.DecodeString(AddBase64Padding(string(text))) if err != nil { return nil, MyErr("VSGRERGBEW-base64.URLEncoding.DecodeString, Possibley Decryption string is too long", err, false) } if (len(decodedMsg) % aes.BlockSize) != 0 { return nil, MyErr("MHETYGVBA-aes.BlockSize-blocksize must be multipe of decoded message length", err, false) } iv := decodedMsg[:aes.BlockSize] msg := decodedMsg[aes.BlockSize:] cfb := cipher.NewCFBDecrypter(block, iv) cfb.XORKeyStream(msg, msg) unpadMsg, err := AesUnpad(msg) if err != nil { return nil, MyErr("WERQFAERGQ-AesUnpad", err, false) } return unpadMsg, nil } func Sha256Hash(data []byte, leng int) []byte { hash := sha256.New() //SHA-3 규격임. hash.Write(data) mdStr := base64.URLEncoding.EncodeToString(hash.Sum(nil)) rtn := "" if leng == 0 { rtn = mdStr } else { rtn = mdStr[10 : 10+leng] } return []byte(rtn) } func Aes256Encrypt(key []byte, nonce []byte, plaintext []byte) ([]byte, error) { // The key argument should be the AES key, either 16 or 32 bytes block, err := aes.NewCipher(key) if err != nil { return nil, MyErr("YBBAERFRYY-NewCipher", err, false) } // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. // nonce := make([]byte, 12) // Do not change 12 // if _, err := io.ReadFull(rand.Reader, nonce); err != nil { // return nil, myErr("io.ReadFull", err) // } aesgcm, err := cipher.NewGCM(block) if err != nil { return nil, MyErr("ERGVSER-cipher.NewGCM", err, false) } text := aesgcm.Seal(nil, nonce, plaintext, nil) return text, nil } func Aes256Decrypt(key []byte, nonce []byte, text []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, MyErr("NSTRFGBSAF-NewCipher", err, false) } aesgcm, err := cipher.NewGCM(block) if err != nil { return nil, MyErr("PQWKKLVASD-cipher.NewGCM", err, false) } plaintext, err := aesgcm.Open(nil, nonce, text, nil) if err != nil { return nil, MyErr("POQWEIRUNVAIK-aesgcm.Open", err, false) } return plaintext, nil }