서명과 검증부터 알고가자
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error)
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
utils.HandleErr(err)
fmt.Println("Private Key", privateKey.D)
fmt.Println("Public Key, X, Y", privateKey.X, privateKey.Y)
func Start() {
message := "Hello Golang"
// 메세지를 Hash 한다.
hashedMessage := utils.Hash(message)
// 공개키, 비밀키 키페어를 생성한다.
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
utils.HandleErr(err)
hashAsBytes, err := hex.DecodeString(hashedMessage)
utils.HandleErr(err)
// Hash된 메세지에 비공개 키로 서명한다.
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashAsBytes)
utils.HandleErr(err)
fmt.Printf("R:%d\nS:%d\n", r, s)
}
누군가 Hash된 메세지에 있는 서명이 너의 서명인지 증명하라고 한다.
→ 공개키만 주면 된다.
Hash된 메세지 + 서명 + (서명에서 만든)공개 키 = true/false
예제
앞서 만든 서명코드를 통해 검증을 진행한다.
message := "Hello Golang"
// ------------------------------------
// [서명]
// 메세지를 Hash 한다.
hashedMessage := utils.Hash(message)
// 공개키, 비밀키 키페어를 생성한다.
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
utils.HandleErr(err)
hashAsBytes, err := hex.DecodeString(hashedMessage)
utils.HandleErr(err)
// Hash된 메세지에 비공개 키로 서명한다.
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashAsBytes)
utils.HandleErr(err)
// -------------------------------------
// [검증]
ok := ecdsa.Verify(&privateKey.PublicKey, hashAsBytes, r, s)
fmt.Println(ok)
// 공개키, 비밀키 키페어를 생성한다.
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
// GenerateKey 함수는 실행할 때마다 새로운 키를 발급해준다.
// Elliptic Curve의 비공개키를 받아서 byte로 변환해주는 함수
keyAsBytes, err := x509.MarshalECPrivateKey(privateKey)
// 비공개키를 16진수 형태로 출력
fmt.Printf("%x\n", keyAsBytes)
utils.HandleErr(err)
hashAsBytes, err := hex.DecodeString(hashedMessage)
utils.HandleErr(err)
// Hash된 메세지에 비공개 키로 서명한다.
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hashAsBytes)
utils.HandleErr(err)
signature := append(r.Bytes(), s.Bytes()...)
// 16진수로 변경한 signature
fmt.Printf("%x\n", signature)
const (
// "Hello Golang"의 Hash된 값
signature string = "3e695e7fba03bf846dc9f948321133dc26ba43045070a7c63d882d2981879624e1eaaf420dd3411e92b355dc987dd027cb7a2b4b88a6279a6b4fc5f24d0f99ca"
hashedMessage string = "8d2caf9f544c5641e94f35c7dc32ebd5d70bd4c92084c5b6644b017df45406f6"
privateKey string = "307702010104204f99a5d356d0721af5bd7fa303ee53bdcc7500db1d17cd1470efe385b513bdf6a00a06082a8648ce3d030107a14403420004653f89e03fdeec0300ced0c7b90c7f72f9dfdbd30c44e6adb345520bebf6cd76d179041a405c71a17fb77e3b41f0ef24c46b23bbae946a5ba6c839629388791d"
)
const (
privateKey string = "307702010104204f99a5d356d0721af5bd7fa303ee53bdcc7500db1d17cd1470efe385b513bdf6a00a06082a8648ce3d030107a14403420004653f89e03fdeec0300ced0c7b90c7f72f9dfdbd30c44e6adb345520bebf6cd76d179041a405c71a17fb77e3b41f0ef24c46b23bbae946a5ba6c839629388791d"
)
// 1. private Key 인코딩 체크
// 해당 함수는 string을 받아 넘겨받은 문자열의 인코딩이 이상하거나 변형되어 있다면 error을 반환한다.
// 정상적이라면 []byte 형태로 반환
privBytes, err := hex.DecodeString(privateKey)
utils.HandleErr(err)
// 해당 함수는 private key를 []byte로 받아 private key를 가져온다.
private, err := x509.ParseECPrivateKey(privBytes)
utils.HandleErr(err)
// 우리가 복구되길 원했던 비공개키와 같은 게 맞는지 아직 확인할 수 없다.
// 이것으로 서명을 검증할 때 확인할 수 있다.
fmt.Println(private)
const (
signature string = "3e695e7fba03bf846dc9f948321133dc26ba43045070a7c63d882d2981879624e1eaaf420dd3411e92b355dc987dd027cb7a2b4b88a6279a6b4fc5f24d0f99ca"
)
// 2. []byte로 변환된 signature를 r과 s로 나눈다.
rBytes := sigBytes[:len(sigBytes)/2]
sBytes := sigBytes[len(sigBytes)/2:]
// 3. big.Int형으로 변환해주기 위해 인스턴스 초기화 진행
var bigR, bigS = big.Int{}, big.Int{}
// 3-1.
bigR.SetBytes(rBytes)
bigS.SetBytes(sBytes)
fmt.Println(bigR, bigS)