Skip to content

Instantly share code, notes, and snippets.

@miguelmota
Last active April 9, 2024 15:28
Show Gist options
  • Save miguelmota/3ea9286bd1d3c2a985b67cac4ba2130a to your computer and use it in GitHub Desktop.
Save miguelmota/3ea9286bd1d3c2a985b67cac4ba2130a to your computer and use it in GitHub Desktop.
Golang RSA encrypt and decrypt example
package ciphers
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"log"
)
// GenerateKeyPair generates a new key pair
func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey) {
privkey, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
log.Error(err)
}
return privkey, &privkey.PublicKey
}
// PrivateKeyToBytes private key to bytes
func PrivateKeyToBytes(priv *rsa.PrivateKey) []byte {
privBytes := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(priv),
},
)
return privBytes
}
// PublicKeyToBytes public key to bytes
func PublicKeyToBytes(pub *rsa.PublicKey) []byte {
pubASN1, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
log.Error(err)
}
pubBytes := pem.EncodeToMemory(&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubASN1,
})
return pubBytes
}
// BytesToPrivateKey bytes to private key
func BytesToPrivateKey(priv []byte) *rsa.PrivateKey {
block, _ := pem.Decode(priv)
enc := x509.IsEncryptedPEMBlock(block)
b := block.Bytes
var err error
if enc {
log.Println("is encrypted pem block")
b, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
log.Error(err)
}
}
key, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
log.Error(err)
}
return key
}
// BytesToPublicKey bytes to public key
func BytesToPublicKey(pub []byte) *rsa.PublicKey {
block, _ := pem.Decode(pub)
enc := x509.IsEncryptedPEMBlock(block)
b := block.Bytes
var err error
if enc {
log.Println("is encrypted pem block")
b, err = x509.DecryptPEMBlock(block, nil)
if err != nil {
log.Error(err)
}
}
ifc, err := x509.ParsePKIXPublicKey(b)
if err != nil {
log.Error(err)
}
key, ok := ifc.(*rsa.PublicKey)
if !ok {
log.Error("not ok")
}
return key
}
// EncryptWithPublicKey encrypts data with public key
func EncryptWithPublicKey(msg []byte, pub *rsa.PublicKey) []byte {
hash := sha512.New()
ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, pub, msg, nil)
if err != nil {
log.Error(err)
}
return ciphertext
}
// DecryptWithPrivateKey decrypts data with private key
func DecryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte {
hash := sha512.New()
plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, priv, ciphertext, nil)
if err != nil {
log.Error(err)
}
return plaintext
@susarlanikhilesh
Copy link

@wongoo According to public and private key cryptography, public key is available to everyone and can be accessed by other users also. But the private key is specific to that particular user, which is used for decryption of data/keys which was encrypted using the users public key.
Eg: RSA, Blowfish, etc.

@wongoo
Copy link

wongoo commented Jul 24, 2019

@susarlanikhilesh I use :

  • public_key_encrypt(sha1(business_data + app_id + app_secret)) as public signature in app client
  • private_key_decrypt(sign) == sha1(business_data + app_id + app_secret) to verify the public signature in server, to make sure the request is from the exact app

app_secret is known for both server&client, is this solution ok?

@susarlanikhilesh
Copy link

@wongoo there is insufficient data for me to understand.
EncryptWithPublicKey(data, publickey)
DecryptWithPrivateKey(data, privatekey)

These functions does not include the integrity check.
Can you please elobrate your question above?

@wongoo
Copy link

wongoo commented Jul 25, 2019

@susarlanikhilesh the common way of signature solution is sign by private key and verify by public key. But I want sign by public key and verify by private key. Through the public key is visible to every one , but appid/appsecret is private, so I think it's security too.
https://gist.github.com/miguelmota/3ea9286bd1d3c2a985b67cac4ba2130a#gistcomment-2979018

@igomez10
Copy link

@wongoo I'm looking for the exact same use case. any luck?

@wongoo
Copy link

wongoo commented Aug 1, 2019

@rfielding
Copy link

do u know why golang not provide public key decrypt and private key encrypt ?

The end result of creating an RSA key is to produce the tuple of numbers (n,d,e). The private key is (n,d), and the public key is (n,e). Even though e is called "encrypt", and d is called "decrypt"; that is just a shorthand. More accurately...

  • (n,e) - public operations ... Verify, Encrypt, because neither of these things require a secret.
  • (n,d) - private operations ... Sign, Decrypt, because both of these require a secret.
  • Sign is the inverse of Verify
  • Decrypt is the inverse of Verify

And be really careful to note that e isn't just "public". It's a small, well-known constant! This is not obvious when you read algebra that explains what RSA does. But somebody needs to tell you what n is to use it with e. Once you have the *big.Int values of (n,d,e), it really is as simple as:

ciphertext = mod_n(plaintext^e)
plaintext = mod_n(ciphertext^d)

msghash = Hash(message)
signature = mod_n(msghash^d)
msghash = mod_n(signature^e)

It is just a matter of whether you apply e or d first. You can't RSA encrypt anything large, so you usually only encrypt keys, or sign hashes. The values being signed or encrypted need to be smaller than n, because in the end they are taken mod_n.

@bentcoder
Copy link

If I put the private and public key string into a flat file and read from there, I always get unable to parse private key: asn1: syntax error: data truncated while calling BytesToPrivateKey - x509.ParsePKCS1PrivateKey(). However, if I just keep them in a variable, it works file. Any reason why would this happen?

pubBytes, err := ioutil.ReadFile("./certs/public.key") // This is fine with Encryption
enc := pkg.Encrypt(msg, pkg.ConvertBytesToPublicKey(pubBytes))

priBytes, err := ioutil.ReadFile("./certs/private.key") // This fails for Dencryption
dec := pkg.Decrypt(enc, pkg.ConvertBytesToPrivateKey(priBytes))

@DaveAppleton
Copy link

Haven't tested it - (about to) but this site shows import and export of keys

https://asecuritysite.com/encryption/gorsa

@bentcoder
Copy link

Haven't tested it - (about to) but this site shows import and export of keys

https://asecuritysite.com/encryption/gorsa

👍 Nice one!

@IzioDev
Copy link

IzioDev commented Oct 14, 2021

Do note that: x509.IsEncryptedPEMBlock and x509.DecryptPEMBlock has both been flagged as insecured by design.

If you have any secure alternative, I'm in!

@quangthe
Copy link

Great work! 👍

@dadencukillia
Copy link

I created a new gist that works with chunks and replaced deprecated methods: https://gist.github.com/dadencukillia/db8e9d0080b5d44bdafa5190d8c04758

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment