Skip to content

Instantly share code, notes, and snippets.

@lynxluna
Created January 1, 2022 11:22
Show Gist options
  • Save lynxluna/031d5ced4c705d29cb2d407acf345581 to your computer and use it in GitHub Desktop.
Save lynxluna/031d5ced4c705d29cb2d407acf345581 to your computer and use it in GitHub Desktop.
Go sign & verify, PHP verify
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io"
"os"
)
func loadPEMPrivateKey(filename string) (*rsa.PrivateKey, error) {
f, err := os.Open(filename)
defer f.Close()
if err != nil {
return nil, err
}
pemTxt, err := io.ReadAll(f)
if err != nil {
return nil, err
}
block, _ := pem.Decode(pemTxt)
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
func loadPEMPublicKey(filename string) (*rsa.PublicKey, error) {
f, err := os.Open(filename)
defer f.Close()
if err != nil {
return nil, err
}
pemTxt, err := io.ReadAll(f)
if err != nil {
return nil, err
}
block, _ := pem.Decode(pemTxt)
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
pub, ok := key.(*rsa.PublicKey)
if !ok {
return nil, fmt.Errorf("%s not a public key", filename)
}
return pub, nil
}
func verifyCommand(arg []string) {
stat, _ := os.Stdin.Stat()
piped := (stat.Mode() & os.ModeCharDevice) == 0
if piped && len(arg) < 3 {
fmt.Println("Commmand: echo sig | rsasign verify pubkey message")
os.Exit(1)
}
if !piped && len(arg) < 4 {
fmt.Println("Command: rsasign verify pubkey message signature")
os.Exit(1)
}
pub, err := loadPEMPublicKey(arg[1])
if err != nil {
fmt.Printf("Cannot read public key %s\n", err)
return
}
var signature []byte
var sigb64 string
if piped {
sigbb, err := io.ReadAll(os.Stdin)
sigb64 = string(sigbb)
if err != nil {
fmt.Printf("Cannot read from stdin %s\n", err)
os.Exit(1)
}
} else {
sigb64 = arg[3]
}
if signature, err = base64.StdEncoding.DecodeString(sigb64); err != nil {
fmt.Printf("Cannot decode signatur %s\n", err)
return
}
opt := rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash,
}
msg := arg[2]
h := sha256.New()
h.Write([]byte(msg))
err = rsa.VerifyPSS(pub, crypto.SHA256, h.Sum(nil), signature, &opt)
if err != nil {
fmt.Printf("Cannot verify message authenticity %s\n", err)
return
}
os.Stderr.WriteString("Signature matched")
os.Exit(0)
}
func signCommand(arg []string) {
if len(arg) < 3 {
fmt.Println("Command: rsasign sign keyfile message")
return
}
priv, err := loadPEMPrivateKey(arg[1])
if err != nil {
fmt.Printf("Cannot read private key %s\n", err)
return
}
msg := arg[2]
h := sha256.New()
h.Write([]byte(msg))
opt := rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash,
}
signature, err := rsa.SignPSS(rand.Reader,
priv,
crypto.SHA256,
h.Sum(nil),
&opt)
if err != nil {
fmt.Println(err)
}
bLen := len(signature)
enc := base64.StdEncoding
l := enc.EncodedLen(bLen)
buf := make([]byte, l)
enc.Encode(buf, signature)
os.Stdout.Write(buf)
}
func main() {
arg := os.Args
if len(arg) < 2 {
fmt.Println("rsasign <command> <params>")
os.Exit(1)
}
sub := arg[1]
switch sub {
case "sign":
signCommand(arg[1:])
case "verify":
verifyCommand(arg[1:])
default:
fmt.Printf("Unknown command: %s", sub)
os.Exit(1)
}
}
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\PublicKeyLoader;
$message = "Hello, World!";
$sigb64 = stream_get_contents(STDIN);
function verifypss($message, $signature) {
$key = PublicKeyLoader::load(file_get_contents('keys/public.pem'));
$key->withPadding(RSA::SIGNATURE_PSS);
return $key->verify($message, $signature) ? 'valid signature' : 'invalid signature';
}
$signature = base64_decode($sigb64);
$result = verifypss($message, $signature);
echo $result;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment