코나 Message Encryption 에 따르면
코나에서 사용하는 API Reqeust , Response 를 필요에 따라 암/복호화 하여 통신한다고 한다.
1. 서버 인증서 :
KONA PLATE에 요청을 보낼 때 클라이언트는 서버 공개 키를 사용하여Message Payload를 암호화하고
KONA PLATE는 서버 개인 키를 사용하여 Payload를 복호화 합니다.
2. 클라이언트 인증서 :
KONA PLATE에서 응답을 받을 때 KONA PLATE는 클라이언트의 공개 키를 사용하여 Payload를 암호화 하고
클라이언트는 서버의 개인 키를 사용하여 복호화 합니다.
클라이언트 인증서를 다운받아보면 아래와 같은 공개키와 개인키를 받게 된다.
-----BEGIN PUBLIC KEY-----
MIIzMgg7XifCKJ2cLxxEZkdBMDiFM+tTYZBVMp/xtr5MrIn9yB2NzZVUEUghjO
-----END PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEBYByPG/YnunrdJ1hehCNFU3EPezeIL87FvuNJNzgmcMAMy9qE+8P0YARQX6OZmtJs7f4S8A0oSmFX9Ne1Nkfwu9O41UWWiN3JoqdNZ/pmqsyTlg9nXyFatsffCmwRoey6U8hNL4vlwwGmrvEvSQ8m+As/YXdPcmbyhVjYAriol5hgPgDNEm9on57N6S7oNbrGex6j+tUe39ARMCcCSL6kfX0wxuedYf24X6DPsQSSEPqD0fowKBgApCmHZ7gx4doaa8NVt+8bReZKozWVZjLfMDdCI2cubu0quh6oxLm0VqaQjC5HgCuDABeBVSkDlYyLrnF3XcklQ6ZgHjvDdFWacfMW2bVpn+Qir0i8WVbXqBmsSfvj5a0QqqZ0vUAvVimlUvWU8CWypTAMQCVBu5zdRKFu8w/O+BAoGBAMeieTVUxG0HRyHbDkTFGj6H5o4TDGyEi1QVvyMSWSm0PBRda2a8XR8PcgM9r+qooQ7ZDzRug47+y6eswH40oePwZMWgUxdyuPNFBraOv7dmKrLAhJRfwjJYC99qF+Q7+5qUSxHOe5O0hyX4I9aPAyHJStraLByDkHwrMdWK1OPLAoGBWTXRZgMfAzTkLPjSGyjEad8YrWIb5lC
-----END PRIVATE KEY-----
해당 RSA 공개키에 대해서 잠깐 설명하면 대칭 및 비대칭 키 암호화에서 사용되는 키 쌍 중 하나이다
이러한 키들은 일반적으로 이진 데이터로 구성되어 있지만 이진 데이터는 읽기가 어렵고 텍스트 형식의 구조에서는 처리하기 까다롭다.
그래서 주로 이진 데이터를 텍스트 형식으로 표현하는데, 그중 하나가 Base64 인코딩이다.
Base64 인코딩은 이진 데이터를 ASCII 문자로 변환하는 인코딩 스키마 중 하나인데 이는 이진 데이터를 텍스트로 표현하기 위한 표준화된 방법중 하나이고 텍스트 기반의 시스템에서는 이진 데이터를 효과적으로 처리할 수 있도록 도와준다
따라서 위에 받은 키는 Base64 로 인코딩된 RSA 키이다.
코나에서는 JOSE(Javascript Object Signing and Encryption) 패키지를 사용해서 자바스크립트 객체를 사용하여
디지털 서명 및 암호화 정의 표준을 사용해서 데이터를 암/복호화 한다.
여기에서 JWE(JSON Web Encryption) 를 사용하는데
JWE 는 JSON 객체에 암호문을 추가하여 데이터를 안전하게 전송하는데 사용된다.
암호화는 대칭 키나 공개/비공개 키 쌍 중 하나늘 사용하여 수행 될수 있다.
샘플 코드의 대략적인 흐름을 보면
RSA 공개키를 가져와서 Base64 디코딩을 수행해 X509 패키지를 통해 공개 키의 사양을 설정하고 RSA 공개 키를 생성한다
X509 는 공개 키 인증서를 표현하기 위한 ITU-T 에서 정의한 표준이고 주로 공개 키 기반의 보안 인프라를 위해 사용된다.
go 에서는 crypto/x509 패키지를 사용하게 되어있고 공개키, 개인키,주체 발급자,만료일자,확장 필드,디지털 서명 의 정보를 포함하는 인증서의 구조가 정의되어 있고 x509.ParsePKIPublicKey 함수는 공개키를 파싱하여 GO 언어 내부 타입으로 변환한다.
1. 생성한 공개/개인 키를 가지고 plainText(직렬화된 json) 를 JWE 로 암호화 한다.
2. JWE 헤더 객체를 생성해서 JWE 알고리즘과 암호화 방법을 설정한다. (코나에서는 RSA_OAEP-256 과 A128GCM 사용)
3. Payload 객체를 생성해서 암호화 데이터 설정
4. JWE 객체를 생성하고 설정한 헤더와 페이로를 설정
5. 최종적으로 해당 객체를 직렬화 하여 암호문을 생성
해당 로직을 go 언어로 작성하게 되면
func EncryptRequest(body interface{}) string {
bodyByte, err := json.Marshal(body)
if err != nil {
panic("Marshal err")
}
crypter, err := jose.NewEncrypter(jose.A128GCM, jose.Recipient{Algorithm: jose.RSA_OAEP, Key: loadPublicKey()}, nil)
if err != nil {
panic("encrypt setting err")
}
obj, err := crypter.Encrypt(bodyByte)
if err != nil {
panic("create encrypt error")
}
encryptBody, err := obj.CompactSerialize()
if err != nil {
panic("compact serialize error")
}
return encryptBody
}
func loadPublicKey() *rsa.PublicKey {
//pemData := []byte(publicKey)
//
//block, rest := pem.Decode(pemData)
//if block == nil {
// panic("pem parsing error")
//}
//
//parseKey, err := x509.ParsePKIXPublicKey(block.Bytes)
//if err != nil {
// panic("x509 parse error")
//}
pemData, err := base64.StdEncoding.DecodeString(publicKey)
if err != nil {
panic("base64 decode error")
}
parseKey, err := x509.ParsePKIXPublicKey(pemData)
if err != nil {
panic("x509 parse error")
}
publicKey, ok := parseKey.(*rsa.PublicKey)
if !ok {
panic("publicKey type error")
}
return publicKey
}
위와 같이 작성할수 있다.
기존에는 base64.StdEncoding.DecodeString 함수를 사용하지 않고 주석처리된 pem.Decode() 를 사용 했었는데
위 두개는 차이점이 있다.
pem.Decode() 함수는 PEM 형식의 데이터를 디코딩 하므로
-----BEGIN PUBLIC KEY-----
MIIzMgg7XifCKJ2cLxxEZkdBMDiFM+tTYZBVMp/xtr5MrIn9yB2NzZVUEUghjO
-----END PUBLIC KEY-----
위와같은 -----BEGIN 과 END 가 즉 블록 시작 및 종료 문자열이 자동 제거가 된다.
하지만 base64.StdEncoding.DecodeString() 을 사용할시 Base64 디코딩만 수행하고 추가적인 문자열 처리가 없으므로 PEM 블록이 포함된 경우 문제가 된다. 따라서 ---BEGIN 과 END 를 제거하고 넣어야 한다.
로컬에서 테스트를 할때 pem.Decode() 를 사용해서 정상적으로 작동했는데
서버에 올렸을때 해당 block == nil 로 잡혀서 서버에서는 제대로 작동하지 않아서 PEM 함수를 Base64 디코딩으로 변경했다.
하지만 왜 안됐는지는 아직 모른다.
'Go' 카테고리의 다른 글
프로그래머스 2024 KAKAO WINTER INTERNSHIP 도넛과 막대 그래프 (0) | 2025.02.11 |
---|---|
프로그래머스 [PCCP 기출문제] 3번 / 충돌위험 찾기 - golang (0) | 2025.02.10 |
golang gin swagger API annotation (0) | 2022.10.24 |
golang http request query 추가 여러 방법 (0) | 2022.10.19 |
네이버 클라우드 플랫폼 카카오톡 알림톡 (golang) (0) | 2022.10.12 |