Golang에서 RSA 사용하기

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

privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
    log.Println("error : ", err)
}
publicKey := &privateKey.PublicKey

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

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 패딩을 선택했다면

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로 바꿔줘야 한다.

OAEPwithSHA-224andMGF1Padding 는 sha256.New224()
OAEPwithSHA-384andMGF1Padding 는 sha512.New384()

224랑 384는 위와 같다.


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로 바꾸는 함수임.
키값 전송할때 —–로 시작하는 문구를 쓰지 않고 키만 직접 전송한다면

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

답글 남기기

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