Last active
June 16, 2021 18:21
-
-
Save kravemir/b003a2926ec5da84a8c38fd1a8c2f4bb to your computer and use it in GitHub Desktop.
This file contains hidden or 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 ( | |
"bytes" | |
"encoding/base64" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"os" | |
"golang.org/x/crypto/openpgp" | |
) | |
const textToEncrypt = "precious and secret!" | |
const secretKeyringLocation = "./.gnupg/secring.gpg" | |
const publicKeyringLocation = "./.gnupg/pubring.gpg" | |
const secretKeyringPassphrase = "123456" | |
func encryptAndSignString(textToEncrypt string) ([]byte, error) { | |
publicEntityList, err := getPublicKeys() | |
if err != nil { | |
return nil, fmt.Errorf("get public keys: %w", err) | |
} | |
privateEntityList, err := getPrivateKeys() | |
if err != nil { | |
return nil, fmt.Errorf("get private keys: %w", err) | |
} | |
var buf bytes.Buffer | |
w, err := openpgp.Encrypt(&buf, publicEntityList, privateEntityList[0], nil, nil) | |
if err != nil { | |
return nil, fmt.Errorf("begin encryption: %w", err) | |
} | |
_, err = w.Write([]byte(textToEncrypt)) | |
if err != nil { | |
return nil, fmt.Errorf("write to encrypt writer: %w", err) | |
} | |
err = w.Close() | |
if err != nil { | |
return nil, fmt.Errorf("close encrypt write: %w", err) | |
} | |
return buf.Bytes(), nil | |
} | |
func decryptToStringAndVerifySignature(encryptedBytes []byte) (string, error) { | |
privateEntityList, err := getPrivateKeys() | |
if err != nil { | |
return "", fmt.Errorf("get private keys: %w", err) | |
} | |
md, err := openpgp.ReadMessage(bytes.NewBuffer(encryptedBytes), privateEntityList, nil, nil) | |
if err != nil { | |
return "", fmt.Errorf("read message: %w", err) | |
} | |
decryptedBytes, err := ioutil.ReadAll(md.UnverifiedBody) | |
if err != nil { | |
return "", fmt.Errorf("read body: %w", err) | |
} | |
err = verifySignature(md) | |
if err != nil { | |
return "", fmt.Errorf("verify signature: %w", err) | |
} | |
return string(decryptedBytes), nil | |
} | |
func verifySignature(md *openpgp.MessageDetails) error { | |
if !md.IsSigned { | |
return fmt.Errorf("not signed") | |
} | |
if md.SignedBy == nil { | |
return fmt.Errorf("missing signature key") | |
} | |
if md.SignatureError != nil { | |
return fmt.Errorf("signature error: %w", md.SignatureError) | |
} | |
return nil | |
} | |
func getPublicKeys() (openpgp.EntityList, error) { | |
return readKeyring(publicKeyringLocation) | |
} | |
func getPrivateKeys() (openpgp.EntityList, error) { | |
entityList, err := readKeyring(secretKeyringLocation) | |
if err != nil { | |
return nil, fmt.Errorf("read secret keyring: %w", err) | |
} | |
entity := entityList[0] | |
passphraseByte := []byte(secretKeyringPassphrase) | |
err = entity.PrivateKey.Decrypt(passphraseByte) | |
if err != nil { | |
return nil, fmt.Errorf("decrypt private key %X: %w", entity.PrivateKey.KeyId, err) | |
} | |
for _, subkey := range entity.Subkeys { | |
err = subkey.PrivateKey.Decrypt(passphraseByte) | |
if err != nil { | |
return nil, fmt.Errorf("decrypt subkey key %X: %w", subkey.PrivateKey.KeyId, err) | |
} | |
} | |
return entityList, nil | |
} | |
func readKeyring(location string) (openpgp.EntityList, error) { | |
keyringFileBuffer, err := os.Open(location) | |
if err != nil { | |
return nil, fmt.Errorf("open keyring: %w", err) | |
} | |
defer keyringFileBuffer.Close() | |
entityList, err := openpgp.ReadKeyRing(keyringFileBuffer) | |
if err != nil { | |
return nil, fmt.Errorf("read keyring: %w", err) | |
} | |
return entityList, nil | |
} | |
func main() { | |
encryptedBytes, err := encryptAndSignString(textToEncrypt) | |
if err != nil { | |
log.Fatal("encrypt error: ", err) | |
} | |
base64EncryptedBytes := base64.StdEncoding.EncodeToString(encryptedBytes) | |
log.Println("Encrypted content in base64:", base64EncryptedBytes) | |
decryptedString, err := decryptToStringAndVerifySignature(encryptedBytes) | |
if err != nil { | |
log.Fatal("decrypt error: ", err) | |
} | |
log.Println("Decrypted content:", decryptedString) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment