Skip to content

Commit

Permalink
update to keyforge and add sign and verify (#113)
Browse files Browse the repository at this point in the history
* update to keyforge and add sign and verify

* oops

* update docker

* Fix integration test - execution request data type updated

---------

Co-authored-by: Maelkum <aleksandar.cekrlic@gmail.com>
  • Loading branch information
dmikey and Maelkum authored Sep 8, 2023
1 parent c03db43 commit 6e8d5f0
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 146 deletions.
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: all
all: clean build-node build-keygen build-manager
all: clean build-node build-keyforge build-manager

.PHONY: test
test:
Expand All @@ -14,10 +14,10 @@ build-node:
cd cmd/node && go build -o ../../dist/b7s
@echo "\n✅ Done.\n"

.PHONY: build-keygen
build-keygen:
.PHONY: build-keyforge
build-keyforge:
@echo "\n🛠 Building node keygen...\n"
cd cmd/keygen && go build -o ../../dist/b7s-keygen
cd cmd/keyforge && go build -o ../../dist/b7s-keyforge
@echo "\n✅ Done.\n"

.PHONY: build-manager
Expand Down
55 changes: 55 additions & 0 deletions cmd/keyforge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## KeyForge

The `keyforge` utility is used for managing cryptographic keys and signing/verifying messages or data. It provides the following options:

### Generate Keys

Generate a new keypair and save it to a file:

$ ./keyforge -o

### Sign and Verify

Sign and verify messages or data using your generated keys:

#### Sign a Message

Sign a message and save the signature:

$ ./keyforge -s "Your message" -o

#### Sign a File

Sign a file and save the signature:

$ ./keyforge -f -o

#### Verify a Signature

Verify a message or file's signature using the \`keyforge\` utility:

$ ./keyforge -pubkey -message "Original message" -signature

#### Verify a Signature with PeerID

Verify a message or file's signature using a PeerID with the \`keyforge\` utility:

$ ./keyforge -peerid -message "Original message" -signature

#### Verify a Signature with OpenSSL

Verify a message or file's signature using OpenSSL:

##### Create a Signature

Use OpenSSL to create a signature:

$ openssl dgst -sha256 -sign -out message.sig

##### Verify a Signature

Use OpenSSL to verify a signature:

$ openssl dgst -sha256 -verify -signature message.sig -in

These commands enable you to manage cryptographic keys and perform signing and verification operations, including using OpenSSL for verification, conveniently within the Blockless b7s Node network.
86 changes: 86 additions & 0 deletions cmd/keyforge/key_management.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package main

import (
"encoding/base64"
"io/ioutil"
"log"
"os"
"path/filepath"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
)

// LoadOrCreateKeys loads existing keys or creates new ones if not present
func LoadOrCreateKeys(privKeyFile string, outputDir string) (crypto.PrivKey, crypto.PubKey, error) {
var priv crypto.PrivKey
var pub crypto.PubKey
var err error

if _, err := os.Stat(privKeyFile); os.IsNotExist(err) {
priv, pub, err = crypto.GenerateKeyPair(crypto.Ed25519, 0)
if err != nil {
return nil, nil, err
}
} else {
privBytes, err := ioutil.ReadFile(privKeyFile)
if err != nil {
return nil, nil, err
}

priv, err = crypto.UnmarshalPrivateKey(privBytes)
if err != nil {
return nil, nil, err
}
pub = priv.GetPublic()
}

privPayload, err := crypto.MarshalPrivateKey(priv)
if err != nil {
log.Fatalf("Could not marshal private key: %s", err)
}

pubPayload, err := crypto.MarshalPublicKey(pub)
if err != nil {
log.Fatalf("Could not marshal public key: %s", err)
}

identity, err := peer.IDFromPublicKey(pub)
if err != nil {
log.Fatalf("Could not generate identity: %s", err)
}

pubKeyFile := filepath.Join(outputDir, pubKeyName)
err = ioutil.WriteFile(pubKeyFile, pubPayload, pubKeyPermissions)
if err != nil {
log.Fatalf("Could not write public key to file: %s", err)
}

pubKeyTextFile := filepath.Join(outputDir, pubKeyTxtName)
pubKeyBase64 := base64.StdEncoding.EncodeToString(pubPayload)
err = ioutil.WriteFile(pubKeyTextFile, []byte(pubKeyBase64), pubKeyPermissions)
if err != nil {
log.Fatalf("Could not write public key text to file: %s", err)
}

identityFile := filepath.Join(outputDir, identityName)
err = ioutil.WriteFile(identityFile, []byte(identity.Pretty()), pubKeyPermissions)
if err != nil {
log.Fatalf("Could not write identity to file: %s", err)
}

privKeyFile = filepath.Join(outputDir, privKeyName)
err = ioutil.WriteFile(privKeyFile, privPayload, privKeyPermissions)
if err != nil {
log.Fatalf("Could not write private key to file: %s", err)
}

// Write peer ID to file
peerIDFile := filepath.Join(outputDir, peerIDFileName)
err = ioutil.WriteFile(peerIDFile, []byte(identity.Pretty()), pubKeyPermissions)
if err != nil {
log.Fatalf("Could not write peer ID to file: %s", err)
}

return priv, pub, nil
}
67 changes: 67 additions & 0 deletions cmd/keyforge/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"log"
"os"
"path/filepath"

"github.com/spf13/pflag"
)

const (
privKeyName = "priv.bin"
pubKeyName = "pub.bin"
pubKeyTxtName = "pubkey.txt"
identityName = "identity"
peerIDFileName = "peerid.txt"
privKeyPermissions = 0600
pubKeyPermissions = 0644

)

func main() {
var (
flagOutputDir string
flagString string
flagFile string
flagPublicKey string
flagMessage string
flagSignature string
flagPeerID string
)

pflag.StringVar(&flagPeerID, "peerid", "", "PeerID for verification")
pflag.StringVarP(&flagOutputDir, "output", "o", ".", "directory where keys should be stored")
pflag.StringVarP(&flagString, "string", "s", "", "string to sign and verify")
pflag.StringVarP(&flagFile, "file", "f", "", "file to sign and verify")
pflag.StringVar(&flagPublicKey, "pubkey", "", "Base64 encoded public key for verification")
pflag.StringVar(&flagMessage, "message", "", "The original message to verify")
pflag.StringVar(&flagSignature, "signature", "", "Base64 encoded signature to verify")

pflag.Parse()

// Initialize output directory
err := os.MkdirAll(flagOutputDir, os.ModePerm)
if err != nil {
log.Fatalf("Could not create output directory: %s", err)
}

privKeyFile := filepath.Join(flagOutputDir, privKeyName)

priv, pub, err := LoadOrCreateKeys(privKeyFile, flagOutputDir)
if err != nil {
log.Fatalf("Error loading or creating keys: %s", err)
}

if flagString != "" || flagFile != "" {
HandleSignAndVerify(priv, pub, flagString, flagFile, flagOutputDir)
}

if flagPublicKey != "" && flagMessage != "" && flagSignature != "" {
VerifyGivenSignature(flagPublicKey, flagMessage, flagSignature)
}

if flagPeerID != "" && flagMessage != "" && flagSignature != "" {
VerifyGivenSignatureWithPeerID(flagPeerID, flagMessage, flagSignature)
}
}
122 changes: 122 additions & 0 deletions cmd/keyforge/sign_verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package main

import (
"encoding/base64"
"fmt"
"io/ioutil"
"log"
"path/filepath"

"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
)

// HandleSignAndVerify performs the signing and verification based on the provided keys and flags
func HandleSignAndVerify(priv crypto.PrivKey, pub crypto.PubKey, flagString string, flagFile string, flagOutput string) {
// Sign and verify string
if flagString != "" {
signature, err := priv.Sign([]byte(flagString))
if err != nil {
log.Fatalf("Could not sign string: %s", err)
}

isValid, err := pub.Verify([]byte(flagString), signature)
if err != nil {
log.Fatalf("Could not verify string: %s", err)
}

signatureStr := base64.StdEncoding.EncodeToString(signature)
if isValid {
fmt.Printf("String signature verified successfully. Signature: %s\n", signatureStr)
} else {
fmt.Println("String signature verification failed.")
}
}

// Sign and verify file
if flagFile != "" {
fileData, err := ioutil.ReadFile(flagFile)
if err != nil {
log.Fatalf("Could not read file: %s", err)
}

fileSignature, err := priv.Sign(fileData)
if err != nil {
log.Fatalf("Could not sign file: %s", err)
}

isFileValid, err := pub.Verify(fileData, fileSignature)
if err != nil {
log.Fatalf("Could not verify file: %s", err)
}

signatureFileStr := base64.StdEncoding.EncodeToString(fileSignature)
if isFileValid {
fmt.Printf("File signature verified successfully. Signature: %s\n", signatureFileStr)
} else {
fmt.Println("File signature verification failed.")
}

if flagOutput != "" {
signatureFilePath := filepath.Join(flagOutput, "file_signature.enc.txt")
err := ioutil.WriteFile(signatureFilePath, []byte(signatureFileStr), 0644)
if err != nil {
log.Fatalf("Could not write signature to file: %s", err)
}
}
}
}

// VerifyGivenSignature verifies a message with a given signature and public key
func VerifyGivenSignature(encodedPubKey string, message string, encodedSignature string) {
pubKeyBytes, err := base64.StdEncoding.DecodeString(encodedPubKey)
if err != nil {
log.Fatalf("Could not decode public key: %s", err)
}

pubKey, err := crypto.UnmarshalPublicKey(pubKeyBytes)
if err != nil {
log.Fatalf("Could not unmarshal public key: %s", err)
}

signatureBytes, err := base64.StdEncoding.DecodeString(encodedSignature)
if err != nil {
log.Fatalf("Could not decode signature: %s", err)
}

isValid, err := pubKey.Verify([]byte(message), signatureBytes)
if err != nil {
log.Fatalf("Could not verify string: %s", err)
}

if isValid {
fmt.Println("Signature verified successfully.")
} else {
fmt.Println("Signature verification failed.")
}
}

// VerifyGivenSignatureWithPeerID verifies a message with a given signature and PeerID
func VerifyGivenSignatureWithPeerID(peerIDStr string, message string, encodedSignature string) {
log.Println("Verifying signature with peerid")
peerID, err := peer.Decode(peerIDStr)
if err != nil {
log.Fatalf("Could not decode PeerID: %s", err)
}

pubKey, err := peerID.ExtractPublicKey()
if err != nil || pubKey == nil {
log.Fatalf("Could not extract public key from PeerID: %s", err)
}

pubKeyBytes, err := crypto.MarshalPublicKey(pubKey)
if err != nil {
log.Fatalf("Could not marshal public key to bytes: %s", err)
}

// This will give you a base64 string representation of the public key
pubKeyBase64 := base64.StdEncoding.EncodeToString(pubKeyBytes)
log.Printf("Extracted public key from PeerID (Base64): %s", pubKeyBase64)

VerifyGivenSignature(pubKeyBase64, message, encodedSignature)
}
23 changes: 0 additions & 23 deletions cmd/keygen/README.md

This file was deleted.

Loading

0 comments on commit 6e8d5f0

Please sign in to comment.