본문 바로가기
IT 초보코딩의 세계/Go 언어

[Block Chain] Go언어의 AES 대칭키, RSA 공개키 알고리즘 2장

by 조이럭키7 2023. 4. 14.
반응형

앞서서(1장에서) 암호화에 대해서 기본 개념을 살펴보았는데 참고하지 못했다면 아래포스팅을 꼭 읽고 2장을 보도록 하자

https://joylucky7.tistory.com/44

 

Go언어의 JSON, 암호화 1장

◆ encoding / json 패키지 이용 ▶ func Marshal(v interface!}) ([]byte, error): Go 언어 자료형을 JSON 텍스트로 변환 ▶ func Marshallndent(v interfaced, prefix, indent string) ([]byte, error): Go 언어 자료형을 JSON 텍스트로 변

joylucky7.tistory.com


◆ AES 대칭키 알고리즘

▶ crypto / aes 패키지의 함수

   ● func NewCipher(key []byte) (cipher.Block, error): 대칭키 암호화 블록 생성

   ● func (c *aesCipher) Encrypt(dst, src []byte): 평문을 AES 알고리즘으로 암호화

   ● func (c *aesCipher) Decrypt(dst, src []byte): AES 알고리즘으로 암호화된 데이터를 평문으로 복호화

 

▶ 암호화 와 복호화

package main

import (
  "crypto/aes"
  "fmt"
)

func main() {
  key := "Hello, Key 12345" // 16바이트
  s := "Hello, world! 12"   // 16바이트

  block, err := aes.NewCipher([]byte(key)) // AES 대칭키 암호화 블록 생성
  if err != nil {
  fmt.Println(err)
  return
  }

  ciphertext := make([]byte, len(s))
  block.Encrypt(ciphertext, []byte(s)) // 평문을 AES 알고리즘으로 암호화
  fmt.Printf("%x\n", ciphertext)

  plaintext := make([]byte, len(s))
  block.Decrypt(plaintext, ciphertext) // AES 알고리즘으로 암호화된 데이터를 평문으로 복호화
  fmt.Println(string(plaintext))
}

▶ crypto / cipher 패키지의 CBC(Ciper Block Chaning) 함수

   ● func NewCBCEncrypter(b Block, iv []byte) BlockMode: 암호화 블록과 초기화 벡터로 암호화 블록 모드 인스턴스 생성

   ● func (x *cbcEncrypter) CryptBlocks(dst, src []byte): 암호화 블록 모드 인스턴스로 암호화

   ● func NewCBCDecrypter(b Block, iv []byte) BlockMode: 암호화 블록과 초기화 벡터로 복호화 블록 모드 인스턴스 생성

   ● func (x *cbcDecrypter) CryptBlocks(dst, src []byte): 복호화 블록 모드 인스턴스로 복호화

package main

import (
  "crypto/aes"
  "crypto/cipher"
  "crypto/rand"
  "fmt"
  "io"
)

func encrypt(b cipher.Block, plaintext []byte) []byte {
  if mod := len(plaintext) % aes.BlockSize; mod != 0 { // 블록 크기의 배수가 되어야함
  padding := make([]byte, aes.BlockSize-mod)   // 블록 크기에서 모자라는 부분을
  plaintext = append(plaintext, padding...)    // 채워줌
  }

  ciphertext := make([]byte, aes.BlockSize+len(plaintext)) // 초기화 벡터 공간(aes.BlockSize)만큼 더 생성
  iv := ciphertext[:aes.BlockSize] // 부분 슬라이스로 초기화 벡터 공간을 가져옴
  if _, err := io.ReadFull(rand.Reader, iv); err != nil { // 랜덤 값을 초기화 벡터에 넣어줌
  fmt.Println(err)
  return nil
  }

  mode := cipher.NewCBCEncrypter(b, iv) // 암호화 블록과 초기화 벡터를 넣어서 암호화 블록 모드 인스턴스 생성
  mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) // 암호화 블록 모드 인스턴스로
                                                                // 암호화
  return ciphertext
}

func decrypt(b cipher.Block, ciphertext []byte) []byte {
  if len(ciphertext)%aes.BlockSize != 0 { // 블록 크기의 배수가 아니면 리턴
  fmt.Println("암호화된 데이터의 길이는 블록 크기의 배수가 되어야합니다.")
  return nil
  }

  iv := ciphertext[:aes.BlockSize]        // 부분 슬라이스로 초기화 벡터 공간을 가져옴
  ciphertext = ciphertext[aes.BlockSize:] // 부분 슬라이스로 암호화된 데이터를 가져옴

  plaintext := make([]byte, len(ciphertext)) // 평문 데이터를 저장할 공간 생성
  mode := cipher.NewCBCDecrypter(b, iv)      // 암호화 블록과 초기화 벡터를 넣어서
                                                   // 복호화 블록 모드 인스턴스 생성
  mode.CryptBlocks(plaintext, ciphertext)    // 복호화 블록 모드 인스턴스로 복호화

  return plaintext
}

func main() {
  key := "Hello Key 123456" // 16바이트

  s := `동해 물과 백두산이 마르고 닳도록
하느님이 보우하사 우리나라 만세.
무궁화 삼천리 화려강산
대한 사람, 대한으로 길이 보전하세.`

  block, err := aes.NewCipher([]byte(key)) // AES 대칭키 암호화 블록 생성
  if err != nil {
  fmt.Println(err)
  return
  }

  ciphertext := encrypt(block, []byte(s)) // 평문을 AES 알고리즘으로 암호화
  fmt.Printf("%x\n", ciphertext)

  plaintext := decrypt(block, ciphertext) // AES 알고리즘 암호문을 평문으로 복호화
  fmt.Println(string(plaintext))

}

◆ RSA 공개키 알고리즘

▶ crypto / rsa 패키지의 함수

   ● func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error): 개인키와 공개키 생성

   ● func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg [ ]byte) (out []byte, err error): 평문을 공개키로 암호화

   ● func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error): 암호화된 데이터를 개인키로 복호화

package main

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

func main() {
  privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // 개인 키와 공개키 생성
  if err != nil {
  fmt.Println(err)
  return
  }
  publicKey := &privateKey.PublicKey // 개인 키 변수 안에 공개 키가 들어있음

  s := `동해 물과 백두산이 마르고 닳도록
하느님이 보우하사 우리나라 만세.
무궁화 삼천리 화려강산
대한 사람, 대한으로 길이 보전하세.`

  ciphertext, err := rsa.EncryptPKCS1v15( // 평문을 공개 키로 암호화
  rand.Reader,
  publicKey, // 공개키
  []byte(s),
  )

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

  plaintext, err := rsa.DecryptPKCS1v15( // 암호화된 데이터를 개인 키로 복호화
  rand.Reader,
  privateKey, // 개인키
  ciphertext,
  )

  fmt.Println(string(plaintext))
}

▶ crypto / rsa 패키지의 서명 / 인증 함수

   ● func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error): 개인키로 서명

   ● func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error): 공개키로 서명 검증

▶ crypto / rsa 패키지의 해시 함수

   ● func New() hash.Hash: MD5 해시 인스턴스 생성

   ● func (d *digest) Write(p []byte) (nn int, err error): 해시 인스턴스에 데이터 추가ㅍ

   ● func (d0 *digest) Sum(in []byte) []byte: 해시 인스턴스에 저장된 데이터의 MD5 해시 값 추출

▶ 서명

package main

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

func main() {
  privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // 개인 키와 공개 키 생성
  if err != nil {
  fmt.Println(err)
  return
  }
  publicKey := &privateKey.PublicKey // 개인 키 변수 안에 공개 키가 들어있음

  message := "안녕하세요. Go 언어"
  hash := md5.New()           // 해시 인스턴스 생성
  hash.Write([]byte(message)) // 해시 인스턴스에 문자열 추가
  digest := hash.Sum(nil)     // 문자열의 MD5 해시 값 추출

  var h1 crypto.Hash
  signature, err := rsa.SignPKCS1v15( // 개인 키로 서명
  rand.Reader,
  privateKey, // 개인 키
  h1,
  digest,     // MD5 해시 값
  )

  var h2 crypto.Hash
  err = rsa.VerifyPKCS1v15( // 공개 키로 서명 검증
  publicKey, // 공개 키
  h2,
  digest,    // MD5 해시 값
  signature, // 서명 값
  )

  if err != nil {
  fmt.Println("검증 실패")
  } else {
  fmt.Println("검증 성공")
  }
}

 

반응형

댓글