WIP crypto prototyping
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
"github.com/k4lipso/pentapass/storage"
|
||||
"github.com/k4lipso/pentapass/crypto/age"
|
||||
"github.com/k4lipso/pentapass/crypto"
|
||||
)
|
||||
|
||||
@@ -33,12 +34,24 @@ var (
|
||||
|
||||
|
||||
func main() {
|
||||
crypto.Encrypt()
|
||||
|
||||
flag.Parse()
|
||||
ctx := context.Background()
|
||||
data := *dbPath
|
||||
|
||||
key, err := age.LoadOrGenerateKeys(*dbPath + "/age.key")
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("AgeKey: %s\n", key.String())
|
||||
fmt.Printf("AgePublicKey: %s\n", key.Recipient().String())
|
||||
|
||||
cipher, err := age.Encrypt([]byte("Test Message"), []string{key.Recipient().String()})
|
||||
fmt.Printf("Encrypted: %s\n", cipher)
|
||||
decrypted, err := age.Decrypt(cipher, key)
|
||||
fmt.Printf("Decrypted: %s\n", decrypted)
|
||||
|
||||
h, dht, err := storage.SetupLibp2pHost(ctx, *dbPath)
|
||||
|
||||
pid := h.ID().String()
|
||||
@@ -77,6 +90,7 @@ func main() {
|
||||
Host: h,
|
||||
Ipfs: ipfs,
|
||||
PubSub: ps,
|
||||
Key: key,
|
||||
}
|
||||
|
||||
Cfg := storage.NewConfig()
|
||||
@@ -214,6 +228,43 @@ Commands:
|
||||
}
|
||||
|
||||
fmt.Printf("[%s] -> %s\n", k, string(v))
|
||||
case "generate":
|
||||
if len(fields) < 3 {
|
||||
fmt.Println("generate <namespace> <Service>")
|
||||
fmt.Println("> ")
|
||||
continue
|
||||
}
|
||||
|
||||
namespace := fields[1]
|
||||
|
||||
val, ok := Namespaces[namespace]
|
||||
|
||||
if !ok {
|
||||
fmt.Println("Namespace does not exist")
|
||||
continue
|
||||
}
|
||||
|
||||
service := fields[2]
|
||||
password := crypto.NewPassword()
|
||||
password.Service = service
|
||||
|
||||
data, err := password.ToJson()
|
||||
if err != nil {
|
||||
printErr(err)
|
||||
continue
|
||||
}
|
||||
|
||||
encryptedPassword, err := age.Encrypt(data, []string{key.Recipient().String()})
|
||||
if err != nil {
|
||||
printErr(err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = val.Put(password.Id.String(), string(encryptedPassword))
|
||||
if err != nil {
|
||||
printErr(err)
|
||||
continue
|
||||
}
|
||||
case "put":
|
||||
if len(fields) < 4 {
|
||||
fmt.Println("put <namespace> <key> <value>")
|
||||
|
||||
113
crypto/age/age.go
Normal file
113
crypto/age/age.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package age
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io"
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"filippo.io/age"
|
||||
)
|
||||
|
||||
var (
|
||||
ageKeyFileName = "age.key"
|
||||
)
|
||||
|
||||
func GenerateAgeKey(filename string) (*age.X25519Identity, error) {
|
||||
// Generate a new X25519 identity (private key)
|
||||
identity, err := age.GenerateX25519Identity()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate identity: %w", err)
|
||||
}
|
||||
|
||||
// Convert the identity to its string representation
|
||||
privateKey := identity.String()
|
||||
|
||||
// Write the private key to a file
|
||||
err = os.WriteFile(filename, []byte(privateKey), 0600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to save private key to file: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Private key saved to %s\n", filename)
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
func LoadAgeKey(filename string) (*age.X25519Identity, error) {
|
||||
// Read the private key from the file
|
||||
privateKeyBytes, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read private key from file: %w", err)
|
||||
}
|
||||
|
||||
// Parse the private key
|
||||
identity, err := age.ParseX25519Identity(string(privateKeyBytes))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
||||
}
|
||||
|
||||
return identity, nil
|
||||
}
|
||||
|
||||
func LoadOrGenerateKeys(filename string) (*age.X25519Identity, error) {
|
||||
_, err := os.Open(filename)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fmt.Println("Not Exists - Generate Keys")
|
||||
return GenerateAgeKey(filename)
|
||||
}
|
||||
|
||||
return LoadAgeKey(filename)
|
||||
}
|
||||
|
||||
func Decrypt(encryptedData []byte, identity *age.X25519Identity) ([]byte, error) {
|
||||
// Create a new decryptor using the recipient's identity
|
||||
decryptor, err := age.Decrypt(bytes.NewReader(encryptedData), identity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create decryptor: %w", err)
|
||||
}
|
||||
|
||||
// Read the decrypted data
|
||||
decryptedData, err := io.ReadAll(decryptor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt data: %w", err)
|
||||
}
|
||||
|
||||
return decryptedData, nil
|
||||
}
|
||||
|
||||
|
||||
func Encrypt(data []byte, recipientKeys []string) ([]byte, error) {
|
||||
var recipients []age.Recipient
|
||||
|
||||
// Parse all recipient keys
|
||||
for _, key := range recipientKeys {
|
||||
recipient, err := age.ParseX25519Recipient(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse recipient key: %w", err)
|
||||
}
|
||||
recipients = append(recipients, recipient)
|
||||
}
|
||||
|
||||
// Create a new buffer to hold the encrypted data
|
||||
var encryptedData bytes.Buffer
|
||||
|
||||
// Create a new age encryptor for the recipients
|
||||
encryptor, err := age.Encrypt(&encryptedData, recipients...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create encryptor: %w", err)
|
||||
}
|
||||
|
||||
// Write the data to the encryptor
|
||||
_, err = encryptor.Write(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt data: %w", err)
|
||||
}
|
||||
|
||||
// Close the encryptor to finalize the encryption process
|
||||
if err := encryptor.Close(); err != nil {
|
||||
return nil, fmt.Errorf("failed to finalize encryption: %w", err)
|
||||
}
|
||||
|
||||
return encryptedData.Bytes(), nil
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"bytes"
|
||||
"io"
|
||||
"encoding/json"
|
||||
|
||||
"filippo.io/age"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Password struct {
|
||||
@@ -15,6 +12,7 @@ type Password struct {
|
||||
Username string `json:"Username"`
|
||||
Password string `json:"Password"`
|
||||
Tags []string `json:"Tags"`
|
||||
Id uuid.UUID `json:"Id"`
|
||||
}
|
||||
|
||||
func (p *Password) ToJson() ([]byte, error) {
|
||||
@@ -32,25 +30,9 @@ func GetPasswordFromJson(b []byte) (Password, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func Encrypt() {
|
||||
publicKey := "age1cy0su9fwf3gf9mw868g5yut09p6nytfmmnktexz2ya5uqg9vl9sss4euqm"
|
||||
recipient, err := age.ParseX25519Recipient(publicKey)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse public key %q: %v", publicKey, err)
|
||||
func NewPassword() *Password {
|
||||
return &Password{
|
||||
Id: uuid.New(),
|
||||
}
|
||||
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
w, err := age.Encrypt(out, recipient)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to create encrypted file: %v\n", err)
|
||||
}
|
||||
if _, err := io.WriteString(w, "Black lives matter."); err != nil {
|
||||
fmt.Printf("Failed to write to encrypted file: %v\n", err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
fmt.Printf("Failed to close encrypted file: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Encrypted file size: %d\n", out.Len())
|
||||
}
|
||||
|
||||
|
||||
147
crypto/rsa/rsa.go
Normal file
147
crypto/rsa/rsa.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package rsa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
"os"
|
||||
"log"
|
||||
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
privateKeyName = "rsa_private_key.pem"
|
||||
publicKeyName = "rsa_public_key.pem"
|
||||
)
|
||||
|
||||
func GenerateKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
// Generate a new RSA key pair
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Save the private key to a file
|
||||
privateKeyPath := path + privateKeyName
|
||||
privateKeyFile, err := os.Create(privateKeyPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer privateKeyFile.Close()
|
||||
|
||||
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
|
||||
})
|
||||
_, err = privateKeyFile.Write(privateKeyPEM)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fmt.Printf("Private key saved to %s\n", privateKeyPath)
|
||||
|
||||
// Extract and save the public key
|
||||
publicKeyPath := path + publicKeyName
|
||||
publicKeyFile, err := os.Create(publicKeyPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer publicKeyFile.Close()
|
||||
|
||||
publicKey := &privateKey.PublicKey
|
||||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
publicKeyPEM := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "RSA PUBLIC KEY",
|
||||
Bytes: publicKeyBytes,
|
||||
})
|
||||
_, err = publicKeyFile.Write(publicKeyPEM)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fmt.Printf("Public key saved to %s\n", publicKeyPath)
|
||||
|
||||
return privateKey, publicKey, nil
|
||||
}
|
||||
|
||||
func LoadKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
// Load private key from file
|
||||
privateKeyPath := path + privateKeyName
|
||||
privateKeyData, err := os.ReadFile(privateKeyPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read private key: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(privateKeyData)
|
||||
if block == nil || block.Type != "RSA PRIVATE KEY" {
|
||||
log.Fatalf("Failed to decode PEM block containing private key")
|
||||
return nil, nil, err
|
||||
}
|
||||
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse private key: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Load public key from file
|
||||
publicKeyPath := path + publicKeyName
|
||||
publicKeyData, err := os.ReadFile(publicKeyPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read public key: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
block, _ = pem.Decode(publicKeyData)
|
||||
if block == nil || block.Type != "RSA PUBLIC KEY" {
|
||||
log.Fatalf("Failed to decode PEM block containing public key")
|
||||
return nil, nil, err
|
||||
}
|
||||
publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse public key: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
publicKey := publicKeyInterface.(*rsa.PublicKey)
|
||||
|
||||
return privateKey, publicKey, nil
|
||||
}
|
||||
|
||||
|
||||
func LoadOrGenerateKeys(path string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
_, err := os.Open(path + privateKeyName)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
fmt.Println("Not Exists - Generate Keys")
|
||||
return GenerateKeys(path)
|
||||
}
|
||||
|
||||
return LoadKeys(path)
|
||||
}
|
||||
|
||||
|
||||
func Encrypt(data []byte, key *rsa.PublicKey) ([]byte, error) {
|
||||
ciphertext, err := rsa.EncryptPKCS1v15(rand.Reader, key, data)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to encrypt: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
func Decrypt(data []byte, key *rsa.PrivateKey) ([]byte, error) {
|
||||
decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, key, data)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decrypt: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return decrypted, nil
|
||||
|
||||
}
|
||||
@@ -31,6 +31,9 @@ import (
|
||||
crypto "github.com/libp2p/go-libp2p/core/crypto"
|
||||
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
|
||||
agelib "filippo.io/age"
|
||||
"github.com/k4lipso/pentapass/crypto/age"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -99,7 +102,7 @@ func SetupLibp2pHost(ctx context.Context, dbPath string) (host host.Host, dht *d
|
||||
|
||||
type Peer struct {
|
||||
Id string
|
||||
//Todo: AgeKey Key
|
||||
Key string
|
||||
}
|
||||
|
||||
type NamespaceConfig struct {
|
||||
@@ -200,6 +203,7 @@ type Namespace struct {
|
||||
//Registry *sharedKeyRegistry
|
||||
CancelFunc context.CancelFunc
|
||||
ctx context.Context
|
||||
Key *agelib.X25519Identity
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +241,15 @@ func (n *Namespace) List() {
|
||||
printErr(err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("[%s] -> %s\n", r.Key, string(r.Value))
|
||||
|
||||
val, err := age.Decrypt(r.Value, n.Key)
|
||||
|
||||
if err != nil {
|
||||
printErr(err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("[%s] -> %s\n", r.Key, string(val))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,6 +264,7 @@ type StorageHandler struct {
|
||||
Host host.Host
|
||||
Ipfs *ipfslite.Peer
|
||||
PubSub *pubsub.PubSub
|
||||
Key *agelib.X25519Identity
|
||||
}
|
||||
|
||||
func IsTrustedPeer(ctx context.Context, id peer.ID, namespace string) bool {
|
||||
@@ -321,7 +334,7 @@ func CreateNamespace(ID string, storageHandler StorageHandler) (*Namespace, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Namespace{ID: ID, Datastore: crdt, CancelFunc: psubCancel, ctx: storageHandler.Ctx}, nil
|
||||
return &Namespace{ID: ID, Datastore: crdt, CancelFunc: psubCancel, ctx: storageHandler.Ctx, Key: storageHandler.Key}, nil
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user