Created
June 8, 2023 11:34
-
-
Save TheAlchemistKE/145b780c68ea0f1b24d551b2d1adeed1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/aes" | |
"crypto/cipher" | |
"crypto/rand" | |
"crypto/rsa" | |
"crypto/sha256" | |
"crypto/x509" | |
"encoding/pem" | |
"fmt" | |
"io/ioutil" | |
"os" | |
) | |
func generateRSAKeyPair() (*rsa.PrivateKey, error) { | |
privateKey, err := rsa.GenerateKey(rand.Reader, 2048) | |
if err != nil { | |
return nil, err | |
} | |
return privateKey, nil | |
} | |
func savePrivateKeyToPEM(privateKey *rsa.PrivateKey, filename string) error { | |
keyBytes := x509.MarshalPKCS1PrivateKey(privateKey) | |
pemBlock := &pem.Block{ | |
Type: "RSA PRIVATE KEY", | |
Bytes: keyBytes, | |
} | |
file, err := os.Create(filename) | |
if err != nil { | |
return err | |
} | |
defer file.Close() | |
err = pem.Encode(file, pemBlock) | |
if err != nil { | |
return err | |
} | |
return nil | |
} | |
func loadPrivateKeyFromPEM(filename string) (*rsa.PrivateKey, error) { | |
file, err := os.Open(filename) | |
if err != nil { | |
return nil, err | |
} | |
defer file.Close() | |
pemData, err := ioutil.ReadAll(file) | |
if err != nil { | |
return nil, err | |
} | |
block, _ := pem.Decode(pemData) | |
if block == nil { | |
return nil, fmt.Errorf("failed to decode PEM block") | |
} | |
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) | |
if err != nil { | |
return nil, err | |
} | |
return privateKey, nil | |
} | |
func savePublicKeyToPEM(publicKey *rsa.PublicKey, filename string) error { | |
keyBytes, err := x509.MarshalPKIXPublicKey(publicKey) | |
if err != nil { | |
return err | |
} | |
pemBlock := &pem.Block{ | |
Type: "PUBLIC KEY", | |
Bytes: keyBytes, | |
} | |
file, err := os.Create(filename) | |
if err != nil { | |
return err | |
} | |
defer file.Close() | |
err = pem.Encode(file, pemBlock) | |
if err != nil { | |
return err | |
} | |
return nil | |
} | |
func loadPublicKeyFromPEM(filename string) (*rsa.PublicKey, error) { | |
file, err := os.Open(filename) | |
if err != nil { | |
return nil, err | |
} | |
defer file.Close() | |
pemData, err := ioutil.ReadAll(file) | |
if err != nil { | |
return nil, err | |
} | |
block, _ := pem.Decode(pemData) | |
if block == nil { | |
return nil, fmt.Errorf("failed to decode PEM block") | |
} | |
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes) | |
if err != nil { | |
return nil, err | |
} | |
return publicKey.(*rsa.PublicKey), nil | |
} | |
func encryptSymmetricKey(publicKey *rsa.PublicKey, symmetricKey []byte) ([]byte, error) { | |
encryptedKey, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, symmetricKey, nil) | |
if err != nil { | |
return nil, err | |
} | |
return encryptedKey, nil | |
} | |
func decryptSymmetricKey(privateKey *rsa.PrivateKey, encryptedKey []byte) ([]byte, error) { | |
decryptedKey, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, encryptedKey, nil) | |
if err != nil { | |
return nil, err | |
} | |
return decryptedKey, nil | |
} | |
func encrypt(plaintext []byte, symmetricKey []byte) ([]byte, error) { | |
block, err := aes.NewCipher(symmetricKey) | |
if err != nil { | |
return nil, err | |
} | |
paddedPlaintext := padPKCS7(plaintext, block.BlockSize()) | |
ciphertext := make([]byte, len(paddedPlaintext)) | |
mode := cipher.NewCBCEncrypter(block, symmetricKey[:block.BlockSize()]) | |
mode.CryptBlocks(ciphertext, paddedPlaintext) | |
return ciphertext, nil | |
} | |
func decrypt(ciphertext []byte, symmetricKey []byte) ([]byte, error) { | |
block, err := aes.NewCipher(symmetricKey) | |
if err != nil { | |
return nil, err | |
} | |
plaintext := make([]byte, len(ciphertext)) | |
mode := cipher.NewCBCDecrypter(block, symmetricKey[:block.BlockSize()]) | |
mode.CryptBlocks(plaintext, ciphertext) | |
unpaddedPlaintext := unpadPKCS7(plaintext) | |
return unpaddedPlaintext, nil | |
} | |
func padPKCS7(data []byte, blockSize int) []byte { | |
padding := blockSize - (len(data) % blockSize) | |
pad := byte(padding) | |
for i := 0; i < padding; i++ { | |
data = append(data, pad) | |
} | |
return data | |
} | |
func unpadPKCS7(data []byte) []byte { | |
padding := int(data[len(data)-1]) | |
return data[:len(data)-padding] | |
} | |
func main() { | |
// Generate RSA key pair | |
privateKey, err := generateRSAKeyPair() | |
if err != nil { | |
fmt.Println("Key generation error:", err) | |
return | |
} | |
// Save private key to PEM file | |
err = savePrivateKeyToPEM(privateKey, "private.pem") | |
if err != nil { | |
fmt.Println("Private key saving error:", err) | |
return | |
} | |
// Load private key from PEM file | |
privateKey, err = loadPrivateKeyFromPEM("private.pem") | |
if err != nil { | |
fmt.Println("Private key loading error:", err) | |
return | |
} | |
// Get the public key from the private key | |
publicKey := privateKey.Public().(*rsa.PublicKey) | |
// Save public key to PEM file | |
err = savePublicKeyToPEM(publicKey, "public.pem") | |
if err != nil { | |
fmt.Println("Public key saving error:", err) | |
return | |
} | |
// Load public key from PEM file | |
publicKey, err = loadPublicKeyFromPEM("public.pem") | |
if err != nil { | |
fmt.Println("Public key loading error:", err) | |
return | |
} | |
// Generate random symmetric key | |
symmetricKey := make([]byte, 32) | |
_, err = rand.Read(symmetricKey) | |
if err != nil { | |
fmt.Println("Symmetric key generation error:", err) | |
return | |
} | |
// Encrypt the symmetric key using the public key | |
encryptedKey, err := encryptSymmetricKey(publicKey, symmetricKey) | |
if err != nil { | |
fmt.Println("Key encryption error:", err) | |
return | |
} | |
// Encrypt the plaintext using the symmetric key | |
plaintext := []byte("Hello, world!") | |
ciphertext, err := encrypt(plaintext, symmetricKey) | |
if err != nil { | |
fmt.Println("Encryption error:", err) | |
return | |
} | |
fmt.Println("encrypted key: ", string(ciphertext)) | |
// Decrypt the symmetric key using the private key | |
decryptedKey, err := decryptSymmetricKey(privateKey, encryptedKey) | |
if err != nil { | |
fmt.Println("Key decryption error:", err) | |
return | |
} | |
// Decrypt the ciphertext using the symmetric key | |
decryptedPlaintext, err := decrypt(ciphertext, decryptedKey) | |
if err != nil { | |
fmt.Println("Decryption error:", err) | |
return | |
} | |
fmt.Println("Decrypted plaintext:", string(decryptedPlaintext)) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment