Golang에서 RSA 사용하기

안드로이드 앱이랑 golang이랑 통신할때 암호화 할려고 golang에서 rsa 쓰는법 연습하던거 여기 정리해둠.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Println("error : ", err)
}
publicKey := &privateKey.PublicKey
privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { log.Println("error : ", err) } publicKey := &privateKey.PublicKey
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
    log.Println("error : ", err)
}
publicKey := &privateKey.PublicKey

Golang에서 RSA-2048로 publcKey와 privateKey 생성은 위와 같이 간단하다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var text = "동해물과 백두산이"
fmt.Println("원본 : ", text)
//공개키로 문자열을 암호화 한다.
encText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(text))
if err != nil {
log.Println("error : ", err)
}
//base64로 인코딩 하는건 디버그 출력으로 보거나 통신할때 쓸려고 하는것이지 굳이 안해도 되긴함.
encTextStr := base64.StdEncoding.EncodeToString(encText)
fmt.Println("암호화 : ", encTextStr)
//base64로 인코딩한거 다시 디코딩해주고 개인키로 복호화를 한다.
encText2, _ := base64.StdEncoding.DecodeString(encTextStr)
decText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encText2)
if err != nil {
log.Println("error : ", err)
}
fmt.Println("복호화 : ", string(decText))
var text = "동해물과 백두산이" fmt.Println("원본 : ", text) //공개키로 문자열을 암호화 한다. encText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(text)) if err != nil { log.Println("error : ", err) } //base64로 인코딩 하는건 디버그 출력으로 보거나 통신할때 쓸려고 하는것이지 굳이 안해도 되긴함. encTextStr := base64.StdEncoding.EncodeToString(encText) fmt.Println("암호화 : ", encTextStr) //base64로 인코딩한거 다시 디코딩해주고 개인키로 복호화를 한다. encText2, _ := base64.StdEncoding.DecodeString(encTextStr) decText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encText2) if err != nil { log.Println("error : ", err) } fmt.Println("복호화 : ", string(decText))
var text = "동해물과 백두산이"
fmt.Println("원본 : ", text)

//공개키로 문자열을 암호화 한다.
encText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(text))
if err != nil {
    log.Println("error : ", err)
}
//base64로 인코딩 하는건 디버그 출력으로 보거나 통신할때 쓸려고 하는것이지 굳이 안해도 되긴함.
encTextStr := base64.StdEncoding.EncodeToString(encText)
fmt.Println("암호화 : ", encTextStr)

//base64로 인코딩한거 다시 디코딩해주고 개인키로 복호화를 한다.
encText2, _ := base64.StdEncoding.DecodeString(encTextStr)
decText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, encText2)
if err != nil {
    log.Println("error : ", err)
}
fmt.Println("복호화 : ", string(decText))

golang용 rsa 라이브러리는 privateKey로 암호화(Encrypt) 하거나 publicKey로 복호화(decrypt) 되지 않음. 안드로이드쪽에서 쓰는 java.security패키지에서는 키 종류와 상관없이 되는데 처음에는 golang에 뭔가 문제가 있는줄 알았지만 검색해보고 golang쪽이 근본적인 논리로는 맞는 방식임.
publicKey는 누구나 볼수 있는 키인데 privateKey로 암호화 하면 그 암호문은 의미가 없어짐
암호화 알고리즘적으로도 문제가 있다는 댓글을 보긴 했는데 이건 잘 모르겠음.


안드로이드에서 RSA 사용할때 위와 같은 패딩 선택하는게 있었는데 PKCS1Padding을 선택했을때 위와 같은 Encrypt, Decrypt를 쓰는거고 OAEP 패딩을 선택했다면

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
encText, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publicKey, []byte(text))
decText, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privateKey, encText2)
encText, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publicKey, []byte(text)) decText, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privateKey, encText2)
encText, err := rsa.EncryptOAEP(sha1.New(), rand.Reader, publicKey, []byte(text))
decText, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, privateKey, encText2)

이 함수를 써야 한다.
그리고 패딩에 보면 SHA-1, SHA-256, SHA-512…  있는데 여기에 맞게 EncryptOAEP, DecryptOAEP 첫번째 인자를 sha1, sha256, sha512로 바꿔줘야 한다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
OAEPwithSHA-224andMGF1Padding 는 sha256.New224()
OAEPwithSHA-384andMGF1Padding 는 sha512.New384()
OAEPwithSHA-224andMGF1Padding 는 sha256.New224() OAEPwithSHA-384andMGF1Padding 는 sha512.New384()
OAEPwithSHA-224andMGF1Padding 는 sha256.New224()
OAEPwithSHA-384andMGF1Padding 는 sha512.New384()

224랑 384는 위와 같다.


Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) {
block, _ := pem.Decode([]byte(pubPEM))
if block == nil {
return nil, errors.New("PEM 파싱에 실패했습니다.")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
switch pub := pub.(type) {
case *rsa.PublicKey:
return pub, nil
default:
break
}
return nil, errors.New("키가 RSA 타입이 아닙니다.")
}
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) { block, _ := pem.Decode([]byte(pubPEM)) if block == nil { return nil, errors.New("PEM 파싱에 실패했습니다.") } pub, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return nil, err } switch pub := pub.(type) { case *rsa.PublicKey: return pub, nil default: break } return nil, errors.New("키가 RSA 타입이 아닙니다.") }
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) {
    block, _ := pem.Decode([]byte(pubPEM))
    if block == nil {
        return nil, errors.New("PEM 파싱에 실패했습니다.")
    }

    pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }

    switch pub := pub.(type) {
    case *rsa.PublicKey:
        return pub, nil
    default:
        break
    }
    return nil, errors.New("키가 RSA 타입이 아닙니다.")
}

“—–BEGIN PUBLIC KEY—–” 으로 시작하는 PEM 방식을 Golang publicKey로 바꾸는 함수임.
키값 전송할때 —–로 시작하는 문구를 쓰지 않고 키만 직접 전송한다면

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) {
tmpStr, err := base64.StdEncoding.DecodeString(pubPEM)
if err != nil {
return nil, err
}
pub, err := x509.ParsePKIXPublicKey(tmpStr)
if err != nil {
return nil, err
}
switch pub := pub.(type) {
case *rsa.PublicKey:
return pub, nil
default:
break
}
return nil, errors.New("키가 RSA 타입이 아닙니다.")
}
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) { tmpStr, err := base64.StdEncoding.DecodeString(pubPEM) if err != nil { return nil, err } pub, err := x509.ParsePKIXPublicKey(tmpStr) if err != nil { return nil, err } switch pub := pub.(type) { case *rsa.PublicKey: return pub, nil default: break } return nil, errors.New("키가 RSA 타입이 아닙니다.") }
func PEMtoPublicKey(pubPEM string) (*rsa.PublicKey, error) {
    tmpStr, err := base64.StdEncoding.DecodeString(pubPEM)
    if err != nil {
        return nil, err
    }
    pub, err := x509.ParsePKIXPublicKey(tmpStr)
    if err != nil {
        return nil, err
    }

    switch pub := pub.(type) {
    case *rsa.PublicKey:
        return pub, nil
    default:
        break
    }
    return nil, errors.New("키가 RSA 타입이 아닙니다.")
}

이런식으로 바꾸면 된다.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
func PEMtoPrivateKey(pubPEM string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(pubPEM))
if block == nil {
return nil, errors.New("PEM 파싱에 실패했습니다.")
}
pri, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return pri, nil
}
func PEMtoPrivateKey(pubPEM string) (*rsa.PrivateKey, error) { block, _ := pem.Decode([]byte(pubPEM)) if block == nil { return nil, errors.New("PEM 파싱에 실패했습니다.") } pri, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, err } return pri, nil }
func PEMtoPrivateKey(pubPEM string) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode([]byte(pubPEM))

    if block == nil {
        return nil, errors.New("PEM 파싱에 실패했습니다.")
    }

    pri, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return pri, nil

}

이건 PrivateKey를 변환할때 사용되고 마찬가지로 —– 부분을 쓰지 않는다면 pem.Decode 부분을 바꾸면 된다.


Comments

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다