Golang'da veri şifreleme ve şifre çözme amacıyla aşağıdaki örneği kullanabilirsiniz. Burada X509 genel ve özel anahtarlar kullanılıyor. Şifreleme ve şifre çözme iki farklı makinede gerçekleşirse bu ideal bir çözümdür. Şifrelenmiş verileri istek gövdesinde kullanabilirsiniz.


Daha kısa sonuçlar için hex kodlayıcıya alternatif olarak base64.URLEncoding/base64.RawStdEncoding işlevlerini kullanabilirsiniz.


Genel ve özel anahtarlar


Genel anahtar gönderene, özel anahtar ise alıcıya aittir. Gönderen düz iletiyi genel anahtarıyla şifreler. Alıcı, özel anahtarıyla şifrelenmiş iletinin şifresini çözer ve tekrardan düz hale getirir. Bu anahtarlar yalnızca bir kez oluşturulur ve kullanılır.


Anahtarları yaratma


Her iki anahtarı da aşağıdaki paketle dize olarak oluşturduktan sonra, bunları sırasıyla "certs/public.key" ve "certs/private.key" dosyalarına kaydedin. Daha sonra gönderici ve alıcı makineler arasında paylaştırın.


// internal/pki
package pki

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
)

type Key struct {
publicKey *rsa.PublicKey
privateKey *rsa.PrivateKey
}

func New() (Key, error) {
var k Key

privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return k, err
}

k.publicKey = &privateKey.PublicKey
k.privateKey = privateKey

return k, nil
}

func (k Key) PublicKeyToPemString() string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: x509.MarshalPKCS1PublicKey(k.publicKey),
},
),
)
}

func (k Key) PrivateKeyToPemString() string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(k.privateKey),
},
),
)
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
key, err := pki.New()
if err != nil {
log.Fatalln(err)
}
fmt.Println(key.PublicKeyToPemString())
fmt.Println(key.PrivateKeyToPemString())
}

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA8kelD7bzkvOl8D9dFAX8wqHzQwJM0cSS/eCOaXAxhX15TgomafXj
B29yJgUEU7Ti/sO3HHURnfCOmr8Fl7Ld/lzfUjkVV16JJBjtWByc+A7pQgnpGnHt
IURQgJaLaRje0q0pw81QxayFHA7Rb/5sNrp1u0fG+ElLwt+TyxfFJdf9Pc9crnOL
I/5+utgqOtcjhTuAxPxijRKlEltRxYs5v8wFfLq6vMQrs10qd9oZie5pfUqS3uOt
Ea8URm+qUipgfMyB5xXopdzK06qCdF4FnNhdLWA3DE5VNCnQVkhP3H5rwWacr0tz
0IfVt2oyRYUpBZbiEQIpwU4KXmnwBKbTtwIDAQAB
-----END RSA PUBLIC KEY-----

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA8kelD7bzkvOl8D9dFAX8wqHzQwJM0cSS/eCOaXAxhX15Tgom
afXjB29yJgUEU7Ti/sO3HHURnfCOmr8Fl7Ld/lzfUjkVV16JJBjtWByc+A7pQgnp
GnHtIURQgJaLaRje0q0pw81QxayFHA7Rb/5sNrp1u0fG+ElLwt+TyxfFJdf9Pc9c
rnOLI/5+utgqOtcjhTuAxPxijRKlEltRxYs5v8wFfLq6vMQrs10qd9oZie5pfUqS
3uOtEa8URm+qUipgfMyB5xXopdzK06qCdF4FnNhdLWA3DE5VNCnQVkhP3H5rwWac
r0tz0IfVt2oyRYUpBZbiEQIpwU4KXmnwBKbTtwIDAQABAoIBABsIA1KNhv+OT6VO
bIQfZuQQTaPcTdXZqMzKkRkSe3P5W99pIoAP/xSFSqcTSDhOpkTmcTermBuXC1IY
nfce7cXDducll0v4MDTm0xRRnPHQOBY2JNveeiaMCK9QHJ3NOI8o4tAFyE1FwlQv
Ew77w/cXNqt+hqSNCPblGwg9zrE6AGO7QPkJcDOPxohUCy6t7WGV/90zat3/e7dn
jQ3qZTSIbtVGnbS5CDZ2uKQ/VT1QgDGBMosMyRQSj1KVo6vF418g9QnaGee2ePx1
EWroo11YQc+dQQdB4NKwlbM+UjS8g+tFZUPVt6Oa34NC3vIeVqIRGwt2HA1sHdQ9
C8G7GAECgYEA+58yc4nkI+GQkqCplhqtkAzkmntLxFR9Vi3nUirKgozkB5iSwslm
IHABVnAh/4AX+MwKbd0iYe5UhgijmHMP74R3WcESDw1QYRaBSKenZ9IdwXL9dn4m
/R/xgYAGPsRsOiY+zxG8cHdrsANunbBQAOPBmfUAb9wEtogcJjVvNEECgYEA9n7V
4kU++ZH5nNV4ZhiPqnRMxAFP/Efn37yQ+LDmI1mkF71QMl8+yA9MvB5oOYaOQ87k
IlZdcBRhuBMM1MNR7baj/uCVXSxr5f7FB2J8+pJN9sLSNFqEDNsIZjry5CxIOkvY
PVPKjNMj4W1RNb0TPWeVhdlONQKwkOI/OVO9KfcCgYEA1YcIalHm/6gIZtXedBoZ
lbfLO2lMJ8THRB3aQrk7d0QWsneAe7orZ3WFPRQVVdwe+6wzYX4aEl8M7V1hbxqd
uFWCbvFP4OQchPdzKPPVNV5yj9qES0zMy1uTN6EsK5HGgiY4gMJ9VjeRdCHFeh3I
FqkwfvURtNtSSJACy03nG8ECgYEAuO+8ZQFzGCfvUT3QETmIQGj1V3Fso2kHjROa
6Rs/73HH7Y+55bEUF2FzPwjJRa+weSt2elS10etYzZRtYgwRIfqP3CB/r+IuKecV
yE6aWhz+pY7RyznGLScAjELaDVsz7ZkN6iU9qJ6ZIv6zmU/8aWuYAU5ioN8dvfYh
XU94c00CgYEA3h/S0omiuEkBM+U8fTZK8GQndDHIkZFtchHYkFQ6WqL5IMJNLDHx
ys29GYK7beW59GHsO9cUJNM0l+lv0KHuGihKpBHtNG3z2r1SzbQqN93XmFQBaNSJ
zWu5OgK8vuAfSCPt4BWeDPReNka/QwbVtBm8O5YIfmLWgKGJtzkT7BM=
-----END RSA PRIVATE KEY-----

Gönderici


Düz iletiyi genel anahtarla şifrelemek için bu paketi kullanın ve ardından alıcıya gönderin.


// internal/pki
package pki

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"io/ioutil"
)

func Encrypt(publicKeyPath, plainText string) (string, error) {
bytes, err := ioutil.ReadFile(publicKeyPath)
if err != nil {
return "", err
}

publicKey, err := convertBytesToPublicKey(bytes)
if err != nil {
return "", err
}

cipher, err := rsa.EncryptOAEP(sha512.New(), rand.Reader, publicKey, []byte(plainText), nil)
if err != nil {
return "", err
}

return cipherToPemString(cipher), nil
}

func convertBytesToPublicKey(keyBytes []byte) (*rsa.PublicKey, error) {
var err error

block, _ := pem.Decode(keyBytes)
blockBytes := block.Bytes
ok := x509.IsEncryptedPEMBlock(block)

if ok {
blockBytes, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
return nil, err
}
}

publicKey, err := x509.ParsePKCS1PublicKey(blockBytes)
if err != nil {
return nil, err
}

return publicKey, nil
}

func cipherToPemString(cipher []byte) string {
return string(
pem.EncodeToMemory(
&pem.Block{
Type: "MESSAGE",
Bytes: cipher,
},
),
)
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
plainText := "This is a very secret message :)"

encryptedMessage, err := pki.Encrypt("./certs/public.key", plainText)
if err != nil {
log.Fatalln(err)
}
fmt.Println(encryptedMessage)
}

-----BEGIN MESSAGE-----
unDCye9RCAad5xSMgu12fP3tUQUJA55llRIPugly7+ljFvR1fy+atyTP5dAryT8A
P0vGjnsjGKU1lMMelN5P6l2YTP9jCYYsntA0rUxMRroxvFuheJ943IHsm6tgArRR
XijTY+dCHjd08EQlOtU5bRmSXsZWBvUBK/s9jzUWDLFTeKXtTSxS2q9YP2DnUebt
kisbrg/bEeHtu9JrMpAl5bDftgqQL/mwbzm/ve5juM2tdfxtgWKKVBpV2WgZ2wMX
ptGHlZ8zIcVRYxE7KRdH7slak+djjhWCHR/sJy1Vp9vjbnZYNQr6wzpGoXSGki9K
pjtot4gahfINgvh0PknUdw==
-----END MESSAGE-----

Alıcı


Özel anahtar ile şifrelenmiş mesajın şifresini çözmek için bu paketi kullanın ve istediğinizi yapın.


// internal/pki
package pki

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"io/ioutil"
)

func Decrypt(privateKeyPath, encryptedMessage string) (string, error) {
bytes, err := ioutil.ReadFile(privateKeyPath)
if err != nil {
return "", err
}

privateKey, err := convertBytesToPrivateKey(bytes)
if err != nil {
return "", err
}

plainMessage, err := rsa.DecryptOAEP(
sha512.New(),
rand.Reader,
privateKey,
pemStringToCipher(encryptedMessage),
nil,
)

return string(plainMessage), err
}

func convertBytesToPrivateKey(keyBytes []byte) (*rsa.PrivateKey, error) {
var err error

block, _ := pem.Decode(keyBytes)
blockBytes := block.Bytes
ok := x509.IsEncryptedPEMBlock(block)

if ok {
blockBytes, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
return nil, err
}
}

privateKey, err := x509.ParsePKCS1PrivateKey(blockBytes)
if err != nil {
return nil, err
}

return privateKey, nil
}

func pemStringToCipher(encryptedMessage string) []byte {
b, _ := pem.Decode([]byte(encryptedMessage))

return b.Bytes
}

package main

import (
"fmt"
"log"

"internal/pki"
)

func main() {
encryptedMessage := // This is the incoming encrypted text as shown above.

decryptedMessage, err := pki.Decrypt("./certs/private.key", encryptedMessage)
if err != nil {
log.Fatalln(err)
}
fmt.Println(decryptedMessage)
}

This is a very secret message :)

Alternatif versiyon


package crypto

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"fmt"
"golang.org/x/crypto/ssh"
"os"
)

type Crypto struct{}

// Encrypt encrypts plain value using SSH public key.
func (c Crypto) Encrypt(plain string) (string, error) {
sshKey, err := c.sshKey("id_rsa.pub")
if err != nil {
return "", fmt.Errorf("get ssh key: %w", err)
}

pubKey, _, _, _, err := ssh.ParseAuthorizedKey(sshKey)
if err != nil {
return "", fmt.Errorf("parse authorised key: %w", err)
}

key := pubKey.(ssh.CryptoPublicKey).CryptoPublicKey().(*rsa.PublicKey)

val, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, key, []byte(plain), nil)
if err != nil {
return "", fmt.Errorf("encrypt: %w", err)
}

return hex.EncodeToString(val), nil
}

// Decrypt decrypts previously encrypted value using SSH private key.
func (c Crypto) Decrypt(encoded string) (string, error) {
sshKey, err := c.sshKey("id_rsa")
if err != nil {
return "", fmt.Errorf("get ssh key: %w", err)
}

decoded, err := hex.DecodeString(encoded)
if err != nil {
return "", fmt.Errorf("decode data: %w", err)
}

pemBlock, _ := pem.Decode(sshKey)
key, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
if err != nil {
return "", fmt.Errorf("parse private key: %w", err)
}

val, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, key, decoded, nil)
if err != nil {
return "", fmt.Errorf("decode: %w", err)
}

return string(val), nil
}

// sshKey returns either a public or private SSH key.
func (c Crypto) sshKey(file string) ([]byte, error) {
home, err := os.UserHomeDir()
if err != nil {
return nil, err
}

key, err := os.ReadFile(fmt.Sprintf("%s/.ssh/%s", home, file))
if err != nil {
return nil, err
}

return key, nil
}