비 대칭키 알고리즘은 공개키 비밀키로 키를 분리하여, 공개키로 암/복호화에 두 키가 요구되는 알고리즘 입니다.

서명, 키 교환 데이터 검증 등 에 사용되며 go 언어는 다양한 비 대칭키 알고리즘을 지원합니다.

이번에는 rsa 알고리즘을 다루겠습니다.

rsa
dsa
ecdsa
ed25519

RSA

비밀키

암호화, 복호화, 서명, 검증 알고리즘을 지원합니다.

다음 명령어로 rsa 알고리즘의 비밀키를 생성합니다.

priv, err := rsa.GenerateKey(rand.Reader, 2048) // 랜덤값 리더, 키 길이

인자로 랜덤 값 리더 키 길이를 입력합니다. 랜덤 값 리더는 go 에서 기본 제공하는 rand.Reader 를 사용합니다.

rand.Reader 는 운용 환경에 따라 적절한 랜덤 시스템 콜을 호출해 줍니다.

공개키

공개키는 비밀키 구조체에 다음 형태로 존재합니다.

priv, _ := rsa.GenerateKey(rand.Reader, 2048) // 랜덤값 리더, 키 길이
pub := priv.PublicKey

공개키로 암호화

다음 함수로 rsa 공개키로 평문을 암호화 합니다.

ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, &pub, msg)
// 랜덤값 리더, 공개키, 평문
// 암호화 예제
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
)

func main() {
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)

	pub := priv.PublicKey

	msg := []byte("i am plain text")
	ciphertext, _ := rsa.EncryptPKCS1v15(rand.Reader, &pub, msg)

	fmt.Printf("%x\n", ciphertext)
}
// 출력
7d19b3d1cd745946915a3cd5a9b0441bf6a676230d5029dbb275d750e1db13d2ba278bb3e7eed2ea25e16bdb7981f113d586b4a84e344e0f33f1cce275bb21f54bba5c9700d3ceed1712e3142040e90976824f295a553333f4baff1bb884e8999f6beba39efce336b3aa7db2805cbb5828e455d7e93b65517c614ebfa5373ed513b346ee231aaafc43a0fe9d50a107101c839913399e4071cd30f2359481ae518c653d31b46ee84ad0b9fe2b4bcaa355da72a3ea21ed7f13e96c56a8235c83af39de574e9efa6a98bea979aacb9e0a99a5a9e90ff1dc4ae8f47bad91a176859c45ea071fc2c334fb6898bb6bee30c64e503e12c0dc748ffcbf7ccea953fad447

출력은 매 실행마다 달라집니다.

비밀키로 복호화

다음 함수로 암호문을 복호화 합니다.

plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
// 랜덤값 리더, 비밀키, 암호문
// 복호화 예제
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"fmt"
)

func main() {
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)

	pub := priv.PublicKey

	msg := []byte("i am plain text")
	ciphertext, _ := rsa.EncryptPKCS1v15(rand.Reader, &pub, msg)

	fmt.Printf("%x\n", ciphertext)

	plaintext, _ := rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)

	fmt.Printf("%s\n", plaintext)
}
// 출력
8366c8e6c2acf9ffb7fc3b9c2059b3067a209eae2a9c60a1c4dc691d9ed7e767f2db08cec0538cdec3abcdcc7a4c4b3d9357b9dffb9898f6d81aaaaf9166fa50137e6ff89add8679980520988b4b79ef7380a76910060fe27f577180c55df866a5f20477fdb932c5d0a1318bed0263db9f132f3d58aeb1304b62e030295afa34bffc696a90e462c58bf0771ef8453a91c531bd1fcfd3d97b3798f3ea8a4b9baea4866435c03e04f2704b65177a9786779ab7bff8f5f6db4ebf38c294f1b1088d5b0dc24118bf27cc1858c07ec2986ca88fdfc5d41890eb92d55c6a771830e57c853bb36dc7834b9e677be1e6b2a9bfe6c7617d54fa836f51126c4e34dcd08ed3
i am plain text

OAEP 암/복호화

Optimal Asymmetric Encryption Padding (OAEP)

rsa 에 패딩과 추가적인 연산으로 암호문으로 평문을 예상할 수 없도록 보안성이 강화된 알고리즘 입니다.

OAEP 암/복호화에는 다음 함수가 사용됩니다.

ciphertext, _ := rsa.EncryptOAEP(sha256.New(), rand.Reader, &pub, msg, nil)
// 사용할 해시, 랜덤 리더, 공개키, 평문, OAEP 레이블

plaintext, _ := rsa.DecryptOAEP(sha256.New(), rand.Reader, priv, ciphertext, nil)
// 사용할 해시, 랜덤 리더, 비밀키, 비문, OAEP 레이블

해시 함수는 보통 SHA256 이 사용됩니다.

// OAEP 암/복호화 예제
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"fmt"
)

func main() {
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)

	pub := priv.PublicKey

	msg := []byte("i am plain text")
	ciphertext, _ := rsa.EncryptOAEP(sha256.New(), rand.Reader, &pub, msg, nil)
	fmt.Printf("%x\n", ciphertext)
	plaintext, _ := rsa.DecryptOAEP(sha256.New(), rand.Reader, priv, ciphertext, nil)
	fmt.Printf("%s\n", plaintext)
}
// 결과
9e122ce4d4deffc5f8750b8339bacb874d17bfb91270539426176adae34a76317f58ecf17b425c1731c15b4f88a3b8846a448aaa8e6df6ea991748185becada497ccefdb75c7c1fac31ea75d8c80907836f9a6a9b384161296b0ed616c5e0a8ce378f620e20f35e513fe990f2c20848f4eba6cf411d7a1aaecfe186ff50a4b9717c78dfc5702a64c0393df1e0c44663853afb511d1eac94574b811ceca21fb74e46993d6fccf394a02ebde5e9c9451482138aaa29b66558ada5fea449465535c8b41080fa88506e033c52e3e58054f4905b50b5770737cad5cf7dd479c2ce8f31718ce423f9455df69a64a1096c3dea86c6d893bf6ae37e0ec5830c7647c8a26
i am plain text